From 3206f0a3016eefea26e7d1ce277c82dee265dfff Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 15:23:21 +0200 Subject: [PATCH 01/26] feat: Gaming on NVIDIA keeps video memory over suspend and installs the 32-bit libraries --- CHANGELOG.md | 4 ++++ lib/menu.sh | 2 +- lib/nvidia.sh | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ steamify.sh | 2 +- 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a821bcf..35deee2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes, per version and per commit. Versions follow `steamify.sh`. Versions before 0.7.0 were numbered afterwards, one per merged pull request. +## 2.11.2 - 2026-10-13 + +- **feat: "Gaming on NVIDIA" also keeps video memory over suspend (`NVreg_PreserveVideoMemoryAllocations=1` in `/etc/modprobe.d/90-steamify-nvidia.conf`, the initramfs is rebuilt), enables `nvidia-suspend`/`nvidia-resume`/`nvidia-hibernate`, and installs `lib32-nvidia-utils` and `lib32-libxkbcommon` (32-bit games, the 32-bit MangoHud preload) on a supported card; off removes only what Steamify added. Untested on hardware yet** + ## 2.11.1 - 2026-10-02 - `d70aeb8` **docs: new README screenshots of the app (2.11 menu) on a Steam Machine and on an NVIDIA PC, and the README names the opt-in "Start Steam silently in desktop mode" and the icons as an option of the conversion** diff --git a/lib/menu.sh b/lib/menu.sh index 20a01b5..22824ae 100644 --- a/lib/menu.sh +++ b/lib/menu.sh @@ -26,7 +26,7 @@ NO_PRESELECT=(boot silent nvsilent cec kpin hdmi extended_controller_support) # FEATURE_BASELINE. FEATURE_BASELINE=2.1.0 declare -A FEATURE_VERSION=( - [gaming]=2.9.0 [boot]=2.1.0 [silent]=2.11.0 [nvidia]=2.10.0 [bigpicture]=2.10.0 [nvsilent]=2.11.0 [theme]=2.1.0 [glyphs]=2.1.0 [single]=2.1.0 + [gaming]=2.9.0 [boot]=2.1.0 [silent]=2.11.0 [nvidia]=2.11.2 [bigpicture]=2.10.0 [nvsilent]=2.11.0 [theme]=2.1.0 [glyphs]=2.1.0 [single]=2.1.0 [launcher]=2.1.0 [cec]=2.7.0 [machine]=2.9.0 [poweroff]=2.2.0 [vram]=2.3.0 [notify]=2.5.0 [steamgame]=2.5.1 [extended_controller_support]=2.10.0 [kpin]=2.1.0 [hdmi]=2.1.0 ) diff --git a/lib/nvidia.sh b/lib/nvidia.sh index 7bc10f7..28eed6c 100644 --- a/lib/nvidia.sh +++ b/lib/nvidia.sh @@ -13,6 +13,11 @@ NVIDIA_INITRAMFS_CONF=${NVIDIA_INITRAMFS_CONF:-/etc/mkinitcpio.conf.d/90-steamif # The script and pacman hook that keep the initramfs file right at every kernel change. NVIDIA_SCRIPT=${NVIDIA_SCRIPT:-/usr/local/libexec/steamify-nvidia-initramfs} NVIDIA_HOOK=${NVIDIA_HOOK:-/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook} +# Keeps video memory over suspend (with the nvidia-suspend/resume services). +NVIDIA_MODPROBE=${NVIDIA_MODPROBE:-/etc/modprobe.d/90-steamify-nvidia.conf} +NVIDIA_SLEEP_UNITS="nvidia-suspend.service nvidia-resume.service nvidia-hibernate.service" +# 32-bit parts Steam games and the 32-bit MangoHud preload need. +NVIDIA_LIB32_PKGS="lib32-nvidia-utils lib32-libxkbcommon" # The running kernel's command line; the tests point this at a file. NVIDIA_CMDLINE=${NVIDIA_CMDLINE:-/proc/cmdline} # The DRM devices in sysfs; the tests point this at a fake tree. @@ -62,6 +67,7 @@ nvidia_enable() { nvidia_write_unit "$unit_args" || return 1 user_systemctl enable "$NVIDIA_UNIT" >/dev/null 2>&1 || { err "Enabling $NVIDIA_UNIT failed."; return 1; } nvidia_kernel_enable || return 1 + nvidia_extras_enable || return 1 ok "Steam starts at your next login." } @@ -70,6 +76,7 @@ nvidia_disable() { user_systemctl disable --now "$NVIDIA_UNIT" >/dev/null 2>&1 rm -f "$unit" user_systemctl daemon-reload + nvidia_extras_disable pkgs="$(state_get nvidia installed_pkgs)" # Only what Steamify installed; games and the Steam folder stay. # shellcheck disable=SC2086 # a list of package names @@ -254,6 +261,48 @@ nvidia_kernel_enable() { return 0 } +nvidia_extras_enable() { + # Video memory kept over sleep, the matching services and the 32-bit libraries (a supported card only). + nvidia_supported || return 0 + local pkg u units="" prev missing=() + if [[ ! -f "$NVIDIA_MODPROBE" ]]; then + info "Keeping video memory over suspend (NVreg_PreserveVideoMemoryAllocations=1)..." + printf '%s\n' '# Added by Steamify (Gaming on NVIDIA)' 'options nvidia NVreg_PreserveVideoMemoryAllocations=1' | + sudo tee "$NVIDIA_MODPROBE" >/dev/null || { err "Writing $NVIDIA_MODPROBE failed."; return 1; } + # The NVIDIA modules load from the initramfs, which carries modprobe.d. + nvidia_rebuild_boot || warn "Rebuilding the initramfs failed: the suspend setting applies once it is rebuilt." + fi + for u in $NVIDIA_SLEEP_UNITS; do + systemctl is-enabled -q "$u" 2>/dev/null && continue + sudo systemctl enable "$u" >/dev/null 2>&1 && units+="${units:+ }$u" + done + if [[ -n "$units" ]]; then + prev="$(state_get nvidia enabled_units)" + state_set nvidia enabled_units "${prev:+$prev }$units" + fi + for pkg in $NVIDIA_LIB32_PKGS; do pacman -Q "$pkg" >/dev/null 2>&1 || missing+=("$pkg"); done + if [[ ${#missing[@]} -gt 0 ]]; then + info "Installing the 32-bit libraries games need: ${missing[*]}" + if sudo pacman -S --needed --noconfirm "${missing[@]}"; then + prev="$(state_get nvidia installed_pkgs)" + state_set nvidia installed_pkgs "${prev:+$prev }${missing[*]}" + else + warn "Installing ${missing[*]} failed (is [multilib] enabled in /etc/pacman.conf?): 32-bit games may not start." + fi + fi + return 0 +} + +nvidia_extras_disable() { + # Only what Steamify enabled; the 32-bit packages go with installed_pkgs. + local u + for u in $(state_get nvidia enabled_units); do sudo systemctl disable "$u" >/dev/null 2>&1; done + if [[ -f "$NVIDIA_MODPROBE" ]]; then + sudo rm -f "$NVIDIA_MODPROBE" + nvidia_rebuild_boot || true + fi +} + nvidia_kernel_disable() { local f changed=0; f="$(nvidia_boot_file)" if [[ -n "$f" ]] && grep -q "$NVIDIA_PARAMS" "$f" 2>/dev/null; then diff --git a/steamify.sh b/steamify.sh index dcfa49a..a87cfdf 100755 --- a/steamify.sh +++ b/steamify.sh @@ -15,7 +15,7 @@ set -uo pipefail # Release version, see CHANGELOG.md. -VERSION=2.11.1 +VERSION=2.11.2 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" From 4461447dedbbcfab4c6e670ce5feb74a6bd30531 Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 18:05:01 +0200 Subject: [PATCH 02/26] chore: keep the gamescope GBM scan-out patch (NVIDIA picture fix) in patches/ --- patches/README.md | 1 + patches/gamescope-gbm-scanout.patch | 1025 +++++++++++++++++++++++++++ 2 files changed, 1026 insertions(+) create mode 100644 patches/gamescope-gbm-scanout.patch diff --git a/patches/README.md b/patches/README.md index b5491af..ef8d40a 100644 --- a/patches/README.md +++ b/patches/README.md @@ -16,3 +16,4 @@ read and reviewed on their own. `lib/*.sh` reads them with `patch_file | `steamify-os-release.sh`, `steamify-os-release.hook` | `lib/login-manager.sh` (SteamOS conversion) | What Steam's System settings show besides the OS name (which stays CachyOS's): `VERSION_ID=steamos-X.Y`, `VERSION_CODENAME=steam-machine`, `VARIANT`/`VARIANT_ID` Steamify with its version, in `/etc/os-release`; the pacman hook runs it again after cachyos-hooks (`fill SCRIPT=... VERSION=... STEAMOS=...`) | | `steamify-nvidia-initramfs.sh`, `steamify-nvidia-initramfs.hook` | `lib/nvidia.sh` (SteamOS conversion, NVIDIA fix) | The pacman hook (before the initramfs is built, after DKMS) and its script: the NVIDIA modules go into the initramfs only while every installed kernel has them, decided again at every kernel or driver change (`fill SCRIPT=...`) | | `cros-ec-cec-single-port.patch` | `lib/cec.sh` (HDMI-CEC) | Makes Valve's Steam Machine CEC driver find amdgpu's HDMI port | +| `gamescope-gbm-scanout.patch` | `lib/nvidia.sh` (gamescope on NVIDIA) | gamescope 3.16.31 patch: scan-out buffers allocated with GBM (opt-in, `gamescope_drm_gbm_scanout=1`), which cures the corrupted picture on NVIDIA; from farnoy/gamescope, see the header of the file | diff --git a/patches/gamescope-gbm-scanout.patch b/patches/gamescope-gbm-scanout.patch new file mode 100644 index 0000000..ed4bc90 --- /dev/null +++ b/patches/gamescope-gbm-scanout.patch @@ -0,0 +1,1025 @@ +GBM-allocated scan-out buffers for gamescope's DRM backend on NVIDIA (opt-in: gamescope_drm_gbm_scanout=1). +Nine commits from https://github.com/farnoy/gamescope (branch nvidia-gbm-wayland: 5cf847274, ffb525cf7, 211f4ca26, +117b593ea, 8da9459ff, cb0378edc, 4e879fbf7, 0c7fddbf3, ae7b99df3), as one diff against gamescope 3.16.31. +Upstream issue: https://github.com/ValveSoftware/gamescope/issues/2309. +Tested on an RTX 5080 (driver 615.78.08): Steam's gaming UI is clean with it and shows artifacts without it. +Applies with `git apply` (it ignores these lines); newer gamescope versions need a rebase. + +diff --git a/README.md b/README.md +index 0f53c60..7de4241 100644 +--- a/README.md ++++ b/README.md +@@ -19,7 +19,7 @@ If running RadeonSI clients with older cards (GFX8 and below), currently have to + + Dependent first (**Debian/Debian-based**): + ``` +-apt install meson ninja-build pkg-config cmake libpipewire-0.3-dev hwdata libx11-dev libwayland-dev libvulkan-dev wayland-protocols libx11-xcb-dev libxdamage-dev libxcomposite-dev libxcursor-dev libxxf86vm-dev libxtst-dev libxres-dev libxmu-dev libxkbcommon-dev libcap-dev libsdl2-dev libavif-dev libpixman-1-dev liblcms2-dev libseat-dev libinput-dev xwayland libxcb-composite0-dev libxcb-ewmh-dev libxcb-icccm4-dev libxcb-res0-dev glslang-tools libluajit-5.1-dev libcatch2-dev ++apt install meson ninja-build pkg-config cmake libpipewire-0.3-dev hwdata libx11-dev libwayland-dev libvulkan-dev libgbm-dev wayland-protocols libx11-xcb-dev libxdamage-dev libxcomposite-dev libxcursor-dev libxxf86vm-dev libxtst-dev libxres-dev libxmu-dev libxkbcommon-dev libcap-dev libsdl2-dev libavif-dev libpixman-1-dev liblcms2-dev libseat-dev libinput-dev xwayland libxcb-composite0-dev libxcb-ewmh-dev libxcb-icccm4-dev libxcb-res0-dev glslang-tools libluajit-5.1-dev libcatch2-dev + ``` + + Build with: +diff --git a/src/Backends/DRMBackend.cpp b/src/Backends/DRMBackend.cpp +index 9aaab7b..9b40f02 100644 +--- a/src/Backends/DRMBackend.cpp ++++ b/src/Backends/DRMBackend.cpp +@@ -56,6 +56,10 @@ + #include "libdisplay-info/cta.h" + #include "wlr_end.hpp" + ++#if HAVE_GBM ++#include "GbmScanoutBuffer.h" ++#endif ++ + #include "gamescope-control-protocol.h" + + extern int g_nPreferredOutputWidth; +@@ -75,6 +79,19 @@ gamescope::ConVar cv_drm_debug_disable_color_range( "drm_debug_disable_col + gamescope::ConVar cv_drm_debug_disable_explicit_sync( "drm_debug_disable_explicit_sync", false, "Force disable explicit sync on the DRM backend." ); + gamescope::ConVar cv_drm_debug_disable_in_fence_fd( "drm_debug_disable_in_fence_fd", false, "Force disable IN_FENCE_FD being set to avoid over-synchronization on the DRM backend." ); + ++gamescope::ConVar cv_drm_gbm_scanout( "drm_gbm_scanout", false, "Allocate scanout buffers with GBM and import them into Vulkan. Fixes corrupted scanout on the NVIDIA proprietary driver.", ++ []( gamescope::ConVar &cvar ) ++ { ++ // The callback also runs for writes of the unchanged value; only an ++ // actual toggle warrants rebuilding the output images. ++ static bool s_bLastValue = false; ++ if ( cvar == s_bLastValue ) ++ return; ++ s_bLastValue = cvar; ++ ++ g_bForceOutputImageRemake = true; ++ }); ++ + gamescope::ConVar cv_drm_allow_dynamic_modes_for_external_display( "drm_allow_dynamic_modes_for_external_display", false, "Allow dynamic mode/refresh rate switching for external displays." ); + + int HackyDRMPresent( const FrameInfo_t *pFrameInfo, bool bAsync ); +@@ -113,6 +130,13 @@ struct drm_t { + bool allow_modifiers; + struct wlr_drm_format_set formats; + ++ // GBM device on a dup of the KMS fd, for backend-allocated scanout ++ // buffers. Buffers keep the device alive via this shared_ptr; the ++ // deleter destroys the device and closes its dup'd fd, so buffer ++ // teardown stays valid even after drm->fd itself is closed. ++ std::shared_ptr gbm; ++ bool bIsNvidia = false; ++ + std::vector< std::unique_ptr< gamescope::CDRMPlane > > planes; + std::vector< std::unique_ptr< gamescope::CDRMCRTC > > crtcs; + std::unordered_map< uint32_t, gamescope::CDRMConnector > connectors; +@@ -547,10 +571,11 @@ namespace gamescope + ~CDRMFb(); + + uint32_t GetFbId() const { return m_uFbId; } +- ++ + private: + uint32_t m_uFbId = 0; + }; ++ + } + + uint32_t g_nDRMFormat = DRM_FORMAT_INVALID; +@@ -1546,6 +1571,28 @@ bool init_drm(struct drm_t *drm, int width, int height, int refresh) + drm->allow_modifiers = true; + } + ++ if ( drmVersion *pVersion = drmGetVersion( drm->fd ) ) ++ { ++ drm->bIsNvidia = pVersion->name && !strcmp( pVersion->name, "nvidia-drm" ); ++ drm_log.infof( "KMS driver: %s", pVersion->name ? pVersion->name : "unknown" ); ++ drmFreeVersion( pVersion ); ++ } ++ ++#if HAVE_GBM ++ // Create the GBM device on a dup of the KMS fd so buffer teardown ++ // (gbm_bo_destroy) stays valid even after wlsession_close_kms() has ++ // closed drm->fd; textures holding GBM buffers can outlive the backend ++ // on shutdown. The deleter closes the dup'd fd after the device. ++ drm->gbm = gamescope::CreateGbmDevice( drm->fd ); ++ if ( !drm->gbm ) ++ drm_log.errorf( "GBM scanout buffers will be unavailable." ); ++ ++ if ( drm->bIsNvidia && !cv_drm_gbm_scanout ) ++ { ++ drm_log.infof( "nvidia-drm detected: scanout of Vulkan-allocated buffers is known to corrupt on this driver. Consider enabling GBM scanout buffers with gamescope_drm_gbm_scanout=1." ); ++ } ++#endif ++ + g_bSupportsAsyncFlips = drmGetCap(drm->fd, DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP, &cap) == 0 && cap != 0; + if (!g_bSupportsAsyncFlips) + drm_log.errorf("Immediate flips are not supported by the KMS driver"); +@@ -1842,6 +1889,12 @@ void finish_drm(struct drm_t *drm) + drm->crtcs.clear(); + drm->connectors.clear(); + ++ // Drop our reference to the GBM device. Outstanding scanout buffers ++ // keep it alive via their own references; the device owns a dup of the ++ // KMS fd, so late gbm_bo_destroy calls stay valid after ++ // wlsession_close_kms() below. ++ drm->gbm = nullptr; ++ + + // Signal the page-flip handler thread to exit and join it so it won't be + // using the DRM fd while we clean it up. Closing the pipe write end +@@ -4227,6 +4280,27 @@ namespace gamescope + return drm_fbid_from_dmabuf( &g_DRM, pDmaBuf ); + } + ++ virtual bool SupportsExternalScanoutBuffers() const override ++ { ++#if HAVE_GBM ++ return g_DRM.gbm != nullptr && g_DRM.allow_modifiers && cv_drm_gbm_scanout; ++#else ++ return false; ++#endif ++ } ++ ++ virtual std::shared_ptr CreateScanoutBuffer( uint32_t uWidth, uint32_t uHeight, uint32_t uDrmFormat, std::span ulModifiers, bool bLinear ) override ++ { ++#if HAVE_GBM ++ if ( !g_DRM.gbm ) ++ return nullptr; ++ ++ return CreateGbmScanoutBuffer( g_DRM.gbm, uWidth, uHeight, uDrmFormat, ulModifiers, bLinear ); ++#else ++ return nullptr; ++#endif ++ } ++ + virtual bool UsesModifiers() const override + { + return g_DRM.allow_modifiers; +diff --git a/src/Backends/DeferredBackend.h b/src/Backends/DeferredBackend.h +index 7f76122..a7385b3 100644 +--- a/src/Backends/DeferredBackend.h ++++ b/src/Backends/DeferredBackend.h +@@ -163,6 +163,25 @@ namespace gamescope + return m_pChild->ImportDmabufToBackend( pDmaBuf ); + } + ++ virtual bool SupportsExternalScanoutBuffers() const override ++ { ++ { ++ std::shared_lock lock{ m_mutInit }; ++ if ( m_bInittedChild ) ++ return m_pChild->SupportsExternalScanoutBuffers(); ++ } ++ return false; ++ } ++ virtual std::shared_ptr CreateScanoutBuffer( uint32_t uWidth, uint32_t uHeight, uint32_t uDrmFormat, std::span ulModifiers, bool bLinear ) override ++ { ++ { ++ std::shared_lock lock{ m_mutInit }; ++ if ( m_bInittedChild ) ++ return m_pChild->CreateScanoutBuffer( uWidth, uHeight, uDrmFormat, ulModifiers, bLinear ); ++ } ++ return nullptr; ++ } ++ + virtual bool UsesModifiers() const override + { + return true; +diff --git a/src/Backends/GbmScanoutBuffer.cpp b/src/Backends/GbmScanoutBuffer.cpp +new file mode 100644 +index 0000000..401f679 +--- /dev/null ++++ b/src/Backends/GbmScanoutBuffer.cpp +@@ -0,0 +1,158 @@ ++#include "GbmScanoutBuffer.h" ++ ++#include "drm_include.h" ++#include "log.hpp" ++ ++#include ++#include ++#include ++ ++#include ++ ++namespace gamescope ++{ ++ static LogScope s_GbmLog( "gbm" ); ++ ++ class CGbmScanoutBuffer final : public IBackendScanoutBuffer ++ { ++ public: ++ CGbmScanoutBuffer( std::shared_ptr pDevice, gbm_bo *pBo, const wlr_dmabuf_attributes &attrs ) ++ : m_pDevice{ std::move( pDevice ) } ++ , m_pBo{ pBo } ++ , m_Attrs{ attrs } ++ { ++ } ++ ++ ~CGbmScanoutBuffer() ++ { ++ wlr_dmabuf_attributes_finish( &m_Attrs ); ++ gbm_bo_destroy( m_pBo ); ++ } ++ ++ const wlr_dmabuf_attributes *GetDmabufAttributes() const override { return &m_Attrs; } ++ ++ private: ++ // Declared before m_pBo so the device outlives the bo. ++ std::shared_ptr m_pDevice; ++ gbm_bo *m_pBo = nullptr; ++ wlr_dmabuf_attributes m_Attrs = {}; ++ }; ++ ++ std::shared_ptr CreateGbmDevice( int nFd ) ++ { ++ int nGbmFd = dup( nFd ); ++ if ( nGbmFd < 0 ) ++ { ++ s_GbmLog.errorf_errno( "Failed to dup fd for GBM" ); ++ return nullptr; ++ } ++ ++ gbm_device *pDevice = gbm_create_device( nGbmFd ); ++ if ( !pDevice ) ++ { ++ close( nGbmFd ); ++ s_GbmLog.errorf( "Failed to create GBM device" ); ++ return nullptr; ++ } ++ ++ s_GbmLog.infof( "Created GBM device (backend: %s)", gbm_device_get_backend_name( pDevice ) ); ++ return std::shared_ptr( pDevice, [ nGbmFd ]( gbm_device *pDevice ){ gbm_device_destroy( pDevice ); close( nGbmFd ); } ); ++ } ++ ++ std::shared_ptr CreateGbmScanoutBuffer( const std::shared_ptr &pDevice, uint32_t uWidth, uint32_t uHeight, uint32_t uDrmFormat, std::span ulModifiers, bool bLinear ) ++ { ++ if ( !pDevice ) ++ return nullptr; ++ ++ uint32_t uFlags = GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT; ++ ++ bool bForceLinearModifier = false; ++ struct gbm_bo *pBo = nullptr; ++ if ( bLinear ) ++ { ++ // GBM rejects GBM_BO_USE_LINEAR combined with an explicit ++ // modifier list (EINVAL in Mesa), so allocate directly. ++ pBo = gbm_bo_create( pDevice.get(), uWidth, uHeight, uDrmFormat, uFlags | GBM_BO_USE_LINEAR ); ++ bForceLinearModifier = true; ++ } ++ else if ( !ulModifiers.empty() ) ++ { ++ pBo = gbm_bo_create_with_modifiers2( pDevice.get(), uWidth, uHeight, uDrmFormat, ulModifiers.data(), ulModifiers.size(), uFlags ); ++ ++ // Some GBM implementations cannot allocate with an explicit ++ // modifier list at all. If only LINEAR was requested, a plain ++ // allocation with GBM_BO_USE_LINEAR is equivalent. ++ if ( !pBo && ulModifiers.size() == 1 && ulModifiers[0] == DRM_FORMAT_MOD_LINEAR ) ++ { ++ pBo = gbm_bo_create( pDevice.get(), uWidth, uHeight, uDrmFormat, uFlags | GBM_BO_USE_LINEAR ); ++ bForceLinearModifier = true; ++ } ++ } ++ ++ if ( !pBo ) ++ { ++ s_GbmLog.errorf( "GBM allocation failed for %ux%u format 0x%x", uWidth, uHeight, uDrmFormat ); ++ return nullptr; ++ } ++ ++ wlr_dmabuf_attributes attrs = ++ { ++ .width = int32_t( uWidth ), ++ .height = int32_t( uHeight ), ++ .format = uDrmFormat, ++ .modifier = bForceLinearModifier ? DRM_FORMAT_MOD_LINEAR : gbm_bo_get_modifier( pBo ), ++ }; ++ ++ const int nPlaneCount = gbm_bo_get_plane_count( pBo ); ++ bool bSuccess = nPlaneCount >= 1 && nPlaneCount <= WLR_DMABUF_MAX_PLANES; ++ ++ if ( bSuccess && !bForceLinearModifier && !Algorithm::Contains( ulModifiers, attrs.modifier ) ) ++ { ++ s_GbmLog.errorf( "GBM returned modifier 0x%" PRIx64 " which was not in the allowed list", attrs.modifier ); ++ bSuccess = false; ++ } ++ ++ // Only count a plane in n_planes once we own its fd, so that ++ // wlr_dmabuf_attributes_finish never closes an fd we didn't acquire. ++ for ( int i = 0; bSuccess && i < nPlaneCount; i++ ) ++ { ++ int nFd = gbm_bo_get_fd_for_plane( pBo, i ); ++ if ( nFd < 0 ) ++ { ++ s_GbmLog.errorf_errno( "gbm_bo_get_fd_for_plane failed" ); ++ bSuccess = false; ++ break; ++ } ++ attrs.fd[i] = nFd; ++ attrs.offset[i] = gbm_bo_get_offset( pBo, i ); ++ attrs.stride[i] = gbm_bo_get_stride_for_plane( pBo, i ); ++ attrs.n_planes = i + 1; ++ } ++ bSuccess = bSuccess && attrs.n_planes == nPlaneCount; ++ ++ // Vulkan's dmabuf memory import is single-fd: all planes must ++ // reference the same underlying buffer. ++ for ( int i = 1; bSuccess && i < attrs.n_planes; i++ ) ++ { ++ struct stat first, other; ++ if ( fstat( attrs.fd[0], &first ) != 0 || fstat( attrs.fd[i], &other ) != 0 || ++ first.st_dev != other.st_dev || first.st_ino != other.st_ino ) ++ { ++ s_GbmLog.errorf( "GBM returned a disjoint multi-plane bo, cannot import" ); ++ bSuccess = false; ++ } ++ } ++ ++ if ( !bSuccess ) ++ { ++ wlr_dmabuf_attributes_finish( &attrs ); ++ gbm_bo_destroy( pBo ); ++ return nullptr; ++ } ++ ++ s_GbmLog.debugf( "allocated %ux%u format 0x%x modifier 0x%" PRIx64 " (%d planes)", ++ uWidth, uHeight, uDrmFormat, attrs.modifier, attrs.n_planes ); ++ ++ return std::make_shared( pDevice, pBo, attrs ); ++ } ++} +diff --git a/src/Backends/GbmScanoutBuffer.h b/src/Backends/GbmScanoutBuffer.h +new file mode 100644 +index 0000000..9dbf3b2 +--- /dev/null ++++ b/src/Backends/GbmScanoutBuffer.h +@@ -0,0 +1,20 @@ ++#pragma once ++ ++#include "backend.h" ++ ++#include ++#include ++#include ++ ++struct gbm_device; ++ ++namespace gamescope ++{ ++ // Creates a GBM device on a dup of nFd. The device owns the dup, so buffers ++ // that hold the device keep working after the caller closes nFd. ++ std::shared_ptr CreateGbmDevice( int nFd ); ++ ++ // Allocates a scanout-capable buffer with GBM_BO_USE_SCANOUT. ulModifiers ++ // must not contain DRM_FORMAT_MOD_INVALID; returns nullptr on failure. ++ std::shared_ptr CreateGbmScanoutBuffer( const std::shared_ptr &pDevice, uint32_t uWidth, uint32_t uHeight, uint32_t uDrmFormat, std::span ulModifiers, bool bLinear ); ++} +diff --git a/src/backend.h b/src/backend.h +index bd57c42..12e4361 100644 +--- a/src/backend.h ++++ b/src/backend.h +@@ -290,6 +290,17 @@ namespace gamescope + virtual ~IBackendPlane() = default; + }; + ++ // A scanout-capable buffer allocated by the backend rather than by Vulkan ++ // (GBM on the DRM backend). Owns the underlying allocation and the fds ++ // inside its wlr_dmabuf_attributes; callers must dup() any fds they keep. ++ class IBackendScanoutBuffer ++ { ++ public: ++ virtual ~IBackendScanoutBuffer() {} ++ ++ virtual const wlr_dmabuf_attributes *GetDmabufAttributes() const = 0; ++ }; ++ + class CBaseBackendFb : public IBackendFb + { + public: +@@ -341,6 +352,19 @@ namespace gamescope + // Rc manages acquire/release of buffer to/from client while imported. + virtual OwningRc ImportDmabufToBackend( wlr_dmabuf_attributes *pDmaBuf ) = 0; + ++ // Whether the backend can allocate scanout-capable buffers itself ++ // (GBM on the DRM backend) for the renderer to import, instead of the ++ // renderer allocating through Vulkan and exporting. ++ virtual bool SupportsExternalScanoutBuffers() const { return false; } ++ // ulModifiers: final allowed modifier list -- already intersected by the ++ // caller across KMS support ( GetSupportedModifiers ) and Vulkan ++ // importability for every format that will alias this buffer. ++ // Never contains DRM_FORMAT_MOD_INVALID. ++ virtual std::shared_ptr CreateScanoutBuffer( uint32_t uWidth, uint32_t uHeight, uint32_t uDrmFormat, std::span ulModifiers, bool bLinear ) ++ { ++ return nullptr; ++ } ++ + virtual bool UsesModifiers() const = 0; + virtual std::span GetSupportedModifiers( uint32_t uDrmFormat ) const = 0; + inline bool SupportsFormat( uint32_t uDrmFormat ) const +diff --git a/src/meson.build b/src/meson.build +index ae3ac16..12fe4ae 100644 +--- a/src/meson.build ++++ b/src/meson.build +@@ -11,6 +11,8 @@ dep_xmu = dependency('xmu') + dep_xi = dependency('xi') + + drm_dep = dependency('libdrm', version: '>= 2.4.113', required: get_option('drm_backend')) ++# gbm_bo_create_with_modifiers2 needs Mesa >= 21.3 ++gbm_dep = dependency('gbm', version: '>= 21.3', required: false) + eis_dep = dependency('libeis-1.0', required : get_option('input_emulation')) + + wayland_server = dependency('wayland-server', version: '>=1.21') +@@ -149,6 +151,11 @@ if sdl2_dep.found() + endif + + gamescope_cpp_args += '-DHAVE_DRM=@0@'.format(drm_dep.found().to_int()) ++have_gbm = drm_dep.found() and gbm_dep.found() ++if have_gbm ++ src += 'Backends/GbmScanoutBuffer.cpp' ++endif ++gamescope_cpp_args += '-DHAVE_GBM=@0@'.format(have_gbm.to_int()) + gamescope_cpp_args += '-DHAVE_SDL2=@0@'.format(sdl2_dep.found().to_int()) + gamescope_cpp_args += '-DHAVE_AVIF=@0@'.format(avif_dep.found().to_int()) + gamescope_cpp_args += '-DHAVE_LIBCAP=@0@'.format(cap_dep.found().to_int()) +@@ -196,7 +203,7 @@ gamescope_version = configure_file( + include_directories : [reshade_include, sol2_include], + dependencies: [ + dep_wayland, dep_x11, dep_xdamage, dep_xcomposite, dep_xrender, dep_xext, dep_xfixes, +- dep_xxf86vm, dep_xres, glm_dep, drm_dep, wayland_server, ++ dep_xxf86vm, dep_xres, glm_dep, drm_dep, gbm_dep, wayland_server, + xkbcommon, thread_dep, sdl2_dep, wlroots_dep, + vulkan_dep, liftoff_dep, dep_xtst, dep_xmu, cap_dep, epoll_dep, pipewire_dep, librt_dep, + stb_dep, displayinfo_dep, openvr_dep, dep_xcursor, avif_dep, dep_xi, +diff --git a/src/rendervulkan.cpp b/src/rendervulkan.cpp +index 54e4efc..cd5769c 100644 +--- a/src/rendervulkan.cpp ++++ b/src/rendervulkan.cpp +@@ -2080,44 +2080,109 @@ static VkImageViewType VulkanImageTypeToViewType(VkImageType type) + } + } + +-bool CVulkanTexture::BInit( uint32_t width, uint32_t height, uint32_t depth, uint32_t drmFormat, createFlags flags, wlr_dmabuf_attributes *pDMA /* = nullptr */, uint32_t contentWidth /* = 0 */, uint32_t contentHeight /* = 0 */, CVulkanTexture *pExistingImageToReuseMemory, gamescope::OwningRc pBackendFb ) ++static VkImageUsageFlags VulkanUsageFromCreateFlags( const CVulkanTexture::createFlags &flags ) + { +- m_pBackendFb = std::move( pBackendFb ); +- m_drmFormat = drmFormat; +- VkResult res = VK_ERROR_INITIALIZATION_FAILED; +- +- VkImageTiling tiling = (flags.bMappable || flags.bLinear) ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL; + VkImageUsageFlags usage = 0; +- VkMemoryPropertyFlags properties; + + if ( flags.bSampled == true ) +- { + usage |= VK_IMAGE_USAGE_SAMPLED_BIT; +- } + + if ( flags.bStorage == true ) +- { + usage |= VK_IMAGE_USAGE_STORAGE_BIT; +- } + + if ( flags.bColorAttachment == true ) +- { + usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; +- } + +- if ( flags.bFlippable == true ) ++ if ( flags.bTransferSrc == true ) ++ usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; ++ ++ if ( flags.bTransferDst == true ) ++ usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; ++ ++ return usage; ++} ++ ++static bool BSupportsExternalScanoutModifier( uint32_t drmFormat, VkImageType imageType, VkImageUsageFlags usage, uint64_t ulModifier ); ++static std::vector GetExternalScanoutModifiers( std::span drmFormats, const CVulkanTexture::createFlags &flags ); ++ ++bool CVulkanTexture::BInit( uint32_t width, uint32_t height, uint32_t depth, uint32_t drmFormat, createFlags flags, wlr_dmabuf_attributes *pDMA /* = nullptr */, uint32_t contentWidth /* = 0 */, uint32_t contentHeight /* = 0 */, CVulkanTexture *pExistingImageToReuseMemory, gamescope::OwningRc pBackendFb, std::shared_ptr pScanoutBuffer ) ++{ ++ // A retry only makes sense when the external scanout buffer was chosen ++ // internally, not handed in by the caller (who then owns the fallback). ++ const bool bCanRetryWithoutExternal = pDMA == nullptr && pScanoutBuffer == nullptr; ++ ++ if ( BInitInternal( width, height, depth, drmFormat, flags, pDMA, contentWidth, contentHeight, pExistingImageToReuseMemory, std::move( pBackendFb ), std::move( pScanoutBuffer ), true ) ) ++ return true; ++ ++ if ( bCanRetryWithoutExternal && m_pScanoutBuffer != nullptr ) + { +- flags.bExportable = true; ++ vk_log.errorf( "Failed to init texture from external scanout buffer, retrying with Vulkan allocation" ); ++ ReleaseResources(); ++ return BInitInternal( width, height, depth, drmFormat, flags, nullptr, contentWidth, contentHeight, pExistingImageToReuseMemory, nullptr, nullptr, false ); + } + +- if ( flags.bTransferSrc == true ) +- { +- usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; ++ return false; ++} ++ ++bool CVulkanTexture::BInitInternal( uint32_t width, uint32_t height, uint32_t depth, uint32_t drmFormat, createFlags flags, wlr_dmabuf_attributes *pDMA, uint32_t contentWidth, uint32_t contentHeight, CVulkanTexture *pExistingImageToReuseMemory, gamescope::OwningRc pBackendFb, std::shared_ptr pScanoutBuffer, bool bAllowExternalScanout ) ++{ ++ m_pBackendFb = std::move( pBackendFb ); ++ m_pScanoutBuffer = std::move( pScanoutBuffer ); ++ m_drmFormat = drmFormat; ++ VkResult res = VK_ERROR_INITIALIZATION_FAILED; ++ ++ VkImageTiling tiling = (flags.bMappable || flags.bLinear) ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL; ++ VkImageUsageFlags usage = VulkanUsageFromCreateFlags( flags ); ++ VkMemoryPropertyFlags properties; ++ ++ // Flippable images are allocated by the backend where supported (GBM on ++ // the DRM backend): scanout memory needs placement only the backend's ++ // allocator can guarantee (physically contiguous vidmem on NVIDIA). ++ // Output images alias two formats in one buffer and are handled by ++ // vulkan_make_output_images_external instead. ++ wlr_dmabuf_attributes externalScanoutAttrs = {}; ++ if ( bAllowExternalScanout && ++ flags.bFlippable && pDMA == nullptr && m_pScanoutBuffer == nullptr && ++ m_pBackendFb == nullptr && ++ !flags.bOutputImage && !flags.bMappable && pExistingImageToReuseMemory == nullptr && ++ flags.imageType == VK_IMAGE_TYPE_2D && depth == 1 && ++ GetBackend()->SupportsExternalScanoutBuffers() && g_device.supportsModifiers() ) ++ { ++ std::vector modifiers; ++ if ( flags.bLinear ) ++ { ++ // Only LINEAR is acceptable here, so probe just that instead of ++ // enumerating every KMS modifier. ++ if ( gamescope::Algorithm::Contains( GetBackend()->GetSupportedModifiers( drmFormat ), uint64_t( DRM_FORMAT_MOD_LINEAR ) ) && ++ BSupportsExternalScanoutModifier( drmFormat, flags.imageType, usage, DRM_FORMAT_MOD_LINEAR ) ) ++ modifiers = { DRM_FORMAT_MOD_LINEAR }; ++ } ++ else ++ { ++ const uint32_t uFormats[1] = { drmFormat }; ++ modifiers = GetExternalScanoutModifiers( uFormats, flags ); ++ } ++ ++ if ( !modifiers.empty() ) ++ m_pScanoutBuffer = GetBackend()->CreateScanoutBuffer( width, height, drmFormat, modifiers, flags.bLinear ); ++ ++ if ( m_pScanoutBuffer ) ++ { ++ externalScanoutAttrs = *m_pScanoutBuffer->GetDmabufAttributes(); ++ pDMA = &externalScanoutAttrs; ++ } ++ else ++ { ++ vk_log.debugf( "External scanout buffer unavailable for format 0x%x, using Vulkan allocation", drmFormat ); ++ } + } + +- if ( flags.bTransferDst == true ) ++ if ( flags.bFlippable == true && pDMA == nullptr ) + { +- usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; ++ // Flippable images we allocate ourselves get exported to the backend. ++ // A flippable image created from an existing dmabuf (eg. a ++ // backend-allocated scanout buffer) is imported instead. ++ flags.bExportable = true; + } + + if ( flags.bMappable == true ) +@@ -2320,7 +2385,8 @@ bool CVulkanTexture::BInit( uint32_t width, uint32_t height, uint32_t depth, uin + vk_errorf( res, "vkCreateImage failed" ); + return false; + } +- ++ m_bOwnsImage = true; ++ + VkMemoryRequirements memRequirements; + g_device.vk.GetImageMemoryRequirements(g_device.device(), m_vkImage, &memRequirements); + +@@ -2383,6 +2449,37 @@ bool CVulkanTexture::BInit( uint32_t width, uint32_t height, uint32_t depth, uin + return false; + } + ++ // A dmabuf import must pick a memory type from the mask ++ // vkGetMemoryFdPropertiesKHR reports for the FD, intersected ++ // with the image's memory requirements - not just any type ++ // satisfying the requirements. ++ VkMemoryFdPropertiesKHR fdProps = { ++ .sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR, ++ }; ++ res = g_device.vk.GetMemoryFdPropertiesKHR( g_device.device(), VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, fd, &fdProps ); ++ if ( res != VK_SUCCESS ) ++ { ++ vk_errorf( res, "vkGetMemoryFdPropertiesKHR failed" ); ++ close( fd ); ++ return false; ++ } ++ ++ const uint32_t uImportTypeBits = memRequirements.memoryTypeBits & fdProps.memoryTypeBits; ++ int32_t nImportMemoryTypeIndex = g_device.findMemoryType( properties, uImportTypeBits ); ++ if ( nImportMemoryTypeIndex < 0 ) ++ { ++ // Fall back to any permitted type; a valid import beats the ++ // preferred property flags. ++ nImportMemoryTypeIndex = g_device.findMemoryType( 0, uImportTypeBits ); ++ } ++ if ( nImportMemoryTypeIndex < 0 ) ++ { ++ vk_log.errorf( "No compatible memory type for dmabuf import" ); ++ close( fd ); ++ return false; ++ } ++ allocInfo.memoryTypeIndex = uint32_t( nImportMemoryTypeIndex ); ++ + // Memory already provided by pDMA + importMemoryInfo = { + .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR, +@@ -2547,13 +2644,43 @@ bool CVulkanTexture::BInit( uint32_t width, uint32_t height, uint32_t depth, uin + + m_dmabuf = dmabuf; + } ++ else if ( pDMA != nullptr && flags.bFlippable == true ) ++ { ++ // Flippable image backed by an external (backend-allocated) dmabuf: ++ // keep our own copy of the attributes for pipewire/screenshots and ++ // for fbid creation. We own these fds; they are closed by ++ // wlr_dmabuf_attributes_finish in ~CVulkanTexture. ++ m_dmabuf = *pDMA; ++ m_dmabuf.n_planes = 0; ++ for ( int i = 0; i < pDMA->n_planes; i++ ) ++ { ++ m_dmabuf.fd[i] = dup( pDMA->fd[i] ); ++ if ( m_dmabuf.fd[i] < 0 ) ++ { ++ vk_log.errorf_errno( "dup failed" ); ++ return false; ++ } ++ m_dmabuf.n_planes = i + 1; ++ } ++ } + +- if ( flags.bFlippable == true ) ++ if ( flags.bFlippable == true && m_pBackendFb == nullptr ) + { + m_pBackendFb = GetBackend()->ImportDmabufToBackend( &m_dmabuf ); ++ if ( pDMA != nullptr && m_pBackendFb == nullptr ) ++ { ++ // For external scanout buffers the whole point is scanning out; ++ // fail so the caller can fall back to Vulkan allocation. ++ vk_log.errorf( "Failed to import external scanout buffer to backend" ); ++ return false; ++ } + } + +- bool bHasAlpha = pDMA ? DRMFormatHasAlpha( pDMA->format ) : true; ++ // Self-allocated scanout buffers (m_pScanoutBuffer) must behave exactly like ++ // the export path above: X-channel formats map to alpha-bearing VkFormats ++ // with identity swizzle, and storage usage stays allowed. Only genuinely ++ // client-imported buffers take the SWIZZLE_ONE/no-storage handling. ++ bool bHasAlpha = ( pDMA && !m_pScanoutBuffer ) ? DRMFormatHasAlpha( pDMA->format ) : true; + + if (!bHasAlpha ) + { +@@ -2742,9 +2869,10 @@ CVulkanTexture::CVulkanTexture( void ) + { + } + +-CVulkanTexture::~CVulkanTexture( void ) ++void CVulkanTexture::ReleaseResources() + { + wlr_dmabuf_attributes_finish( &m_dmabuf ); ++ m_dmabuf = {}; + + if ( m_pMappedData != nullptr && m_vkImageMemory ) + { +@@ -2764,24 +2892,47 @@ CVulkanTexture::~CVulkanTexture( void ) + m_linearView = VK_NULL_HANDLE; + } + ++ if ( m_lumaView != VK_NULL_HANDLE ) ++ { ++ g_device.vk.DestroyImageView( g_device.device(), m_lumaView, nullptr ); ++ m_lumaView = VK_NULL_HANDLE; ++ } ++ ++ if ( m_chromaView != VK_NULL_HANDLE ) ++ { ++ g_device.vk.DestroyImageView( g_device.device(), m_chromaView, nullptr ); ++ m_chromaView = VK_NULL_HANDLE; ++ } ++ + if ( m_pBackendFb != nullptr ) + m_pBackendFb = nullptr; + +- if ( m_vkImageMemory != VK_NULL_HANDLE ) ++ // Images we created are destroyed even when the memory isn't ours ++ // (aliased textures, or an init that failed before allocating memory). ++ // Swapchain-owned images are never destroyed here. ++ if ( m_vkImage != VK_NULL_HANDLE && m_bOwnsImage ) + { +- if ( m_vkImage != VK_NULL_HANDLE ) +- { +- g_device.vk.DestroyImage( g_device.device(), m_vkImage, nullptr ); +- m_vkImage = VK_NULL_HANDLE; +- } ++ g_device.vk.DestroyImage( g_device.device(), m_vkImage, nullptr ); ++ } ++ m_vkImage = VK_NULL_HANDLE; ++ m_bOwnsImage = false; + ++ if ( m_vkImageMemory != VK_NULL_HANDLE ) ++ { + g_device.vk.FreeMemory( g_device.device(), m_vkImageMemory, nullptr ); + m_vkImageMemory = VK_NULL_HANDLE; + } + ++ m_pScanoutBuffer = nullptr; ++ + m_bInitialized = false; + } + ++CVulkanTexture::~CVulkanTexture( void ) ++{ ++ ReleaseResources(); ++} ++ + int CVulkanTexture::memoryFence() + { + const VkMemoryGetFdInfoKHR memory_get_fd_info = { +@@ -3341,6 +3492,139 @@ bool vulkan_remake_swapchain( void ) + return bRet; + } + ++// Whether Vulkan can create + import a dmabuf image with this ++// format/modifier and usage. Uses the same srgb/linear mutable-format view ++// pair the real image in BInitInternal is created with. ++static bool BSupportsExternalScanoutModifier( uint32_t drmFormat, VkImageType imageType, VkImageUsageFlags usage, uint64_t ulModifier ) ++{ ++ VkImageCreateInfo imageInfo = { ++ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, ++ .imageType = imageType, ++ .format = DRMFormatToVulkan( drmFormat, false ), ++ .mipLevels = 1, ++ .arrayLayers = 1, ++ .samples = VK_SAMPLE_COUNT_1_BIT, ++ .tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT, ++ .usage = usage, ++ .sharingMode = VK_SHARING_MODE_EXCLUSIVE, ++ }; ++ ++ std::array formats = { ++ DRMFormatToVulkan( drmFormat, false ), ++ DRMFormatToVulkan( drmFormat, true ), ++ }; ++ ++ VkImageFormatListCreateInfo formatList = { ++ .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO, ++ .viewFormatCount = (uint32_t)formats.size(), ++ .pViewFormats = formats.data(), ++ }; ++ ++ if ( formats[0] != formats[1] ) ++ { ++ formatList.pNext = std::exchange( imageInfo.pNext, &formatList ); ++ imageInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; ++ } ++ ++ VkExternalImageFormatProperties externalImageProperties = { ++ .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES, ++ }; ++ ++ VkResult res = getModifierProps( &imageInfo, ulModifier, &externalImageProperties ); ++ return res == VK_SUCCESS && ++ !!( externalImageProperties.externalMemoryProperties.externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT ); ++} ++ ++// Modifiers that (a) the backend can scan out for every format in drmFormats, ++// and (b) Vulkan can create + import a dmabuf image with, using the usage ++// implied by the given createFlags, for every format in drmFormats. ++// This is the "plane ∩ renderer" intersection other compositors (eg. KWin) ++// use when allocating scanout buffers through GBM, extended across all ++// formats that will alias the same buffer. ++static std::vector GetExternalScanoutModifiers( std::span drmFormats, const CVulkanTexture::createFlags &flags ) ++{ ++ std::vector modifiers; ++ if ( drmFormats.empty() ) ++ return modifiers; ++ ++ const VkImageUsageFlags usage = VulkanUsageFromCreateFlags( flags ); ++ ++ for ( uint64_t modifier : GetBackend()->GetSupportedModifiers( drmFormats[0] ) ) ++ { ++ if ( modifier == DRM_FORMAT_MOD_INVALID ) ++ continue; ++ ++ bool bCompatible = true; ++ for ( uint32_t drmFormat : drmFormats ) ++ { ++ if ( !gamescope::Algorithm::Contains( GetBackend()->GetSupportedModifiers( drmFormat ), modifier ) || ++ !BSupportsExternalScanoutModifier( drmFormat, flags.imageType, usage, modifier ) ) ++ { ++ bCompatible = false; ++ break; ++ } ++ } ++ ++ if ( bCompatible ) ++ modifiers.push_back( modifier ); ++ } ++ ++ return modifiers; ++} ++ ++// Allocate the output images through the backend (GBM on DRM) and import ++// them into Vulkan, instead of allocating with Vulkan and exporting. ++// Fixes scanout on drivers that need special placement for scanout memory ++// (NVIDIA needs physical contiguity, which only its GBM path guarantees). ++static bool vulkan_make_output_images_external( VulkanOutput_t *pOutput, const CVulkanTexture::createFlags &outputImageflags, uint32_t uOutputWidth, uint32_t uOutputHeight ) ++{ ++ uint32_t uFormats[2] = { pOutput->uOutputFormat, DRM_FORMAT_INVALID }; ++ size_t nFormats = 1; ++ ++ const bool bOverlay = pOutput->uOutputFormatOverlay != VK_FORMAT_UNDEFINED && !kDisablePartialComposition; ++ if ( bOverlay ) ++ uFormats[nFormats++] = pOutput->uOutputFormatOverlay; ++ ++ std::vector modifiers = GetExternalScanoutModifiers( std::span( uFormats, nFormats ), outputImageflags ); ++ if ( modifiers.empty() ) ++ { ++ vk_log.errorf( "No modifier is scanout-capable and Vulkan-importable for all output formats" ); ++ return false; ++ } ++ ++ for ( size_t i = 0; i < 3; i++ ) ++ { ++ std::shared_ptr pScanoutBuffer = ++ GetBackend()->CreateScanoutBuffer( uOutputWidth, uOutputHeight, pOutput->uOutputFormat, modifiers, false ); ++ if ( !pScanoutBuffer ) ++ return false; ++ ++ // BInit never takes ownership of these attrs' fds; it dups what it keeps. ++ wlr_dmabuf_attributes attrs = *pScanoutBuffer->GetDmabufAttributes(); ++ ++ pOutput->outputImages[i] = new CVulkanTexture(); ++ if ( !pOutput->outputImages[i]->BInit( uOutputWidth, uOutputHeight, 1u, pOutput->uOutputFormat, outputImageflags, &attrs, 0, 0, nullptr, nullptr, pScanoutBuffer ) ) ++ return false; ++ ++ if ( bOverlay ) ++ { ++ // The overlay image is a second import of the same buffer with ++ // the overlay format: identical modifier and plane layout ++ // (both formats are 32bpp, so strides match), its own fbid, and ++ // its own kernel reference on the underlying memory. Both ++ // textures share the IBackendScanoutBuffer. ++ attrs = *pScanoutBuffer->GetDmabufAttributes(); ++ attrs.format = pOutput->uOutputFormatOverlay; ++ ++ pOutput->outputImagesPartialOverlay[i] = new CVulkanTexture(); ++ if ( !pOutput->outputImagesPartialOverlay[i]->BInit( uOutputWidth, uOutputHeight, 1u, pOutput->uOutputFormatOverlay, outputImageflags, &attrs, 0, 0, nullptr, nullptr, pScanoutBuffer ) ) ++ return false; ++ } ++ } ++ ++ return true; ++} ++ + static bool vulkan_make_output_images( VulkanOutput_t *pOutput ) + { + CVulkanTexture::createFlags outputImageflags; +@@ -3360,14 +3644,30 @@ static bool vulkan_make_output_images( VulkanOutput_t *pOutput ) + pOutput->outputImagesPartialOverlay[1] = nullptr; + pOutput->outputImagesPartialOverlay[2] = nullptr; + +- uint32_t uDRMFormat = pOutput->uOutputFormat; +- + // Output images are physical-oriented; the panel scans out unrotated. + uint32_t uOutputWidth = g_nOutputWidth; + uint32_t uOutputHeight = g_nOutputHeight; + if ( g_uOutputRotation & 1u ) + std::swap( uOutputWidth, uOutputHeight ); + ++ if ( GetBackend()->SupportsExternalScanoutBuffers() && g_device.supportsModifiers() ) ++ { ++ if ( vulkan_make_output_images_external( pOutput, outputImageflags, uOutputWidth, uOutputHeight ) ) ++ { ++ // Oh no. ++ pOutput->temporaryHackyBlankImage = vulkan_create_debug_blank_texture(); ++ return true; ++ } ++ ++ vk_log.errorf( "Failed to create backend (GBM) scanout buffers, falling back to Vulkan allocation" ); ++ for ( auto &pImage : pOutput->outputImages ) ++ pImage = nullptr; ++ for ( auto &pImage : pOutput->outputImagesPartialOverlay ) ++ pImage = nullptr; ++ } ++ ++ uint32_t uDRMFormat = pOutput->uOutputFormat; ++ + pOutput->outputImages[0] = new CVulkanTexture(); + bool bSuccess = pOutput->outputImages[0]->BInit( uOutputWidth, uOutputHeight, 1u, uDRMFormat, outputImageflags ); + if ( bSuccess != true ) +diff --git a/src/rendervulkan.hpp b/src/rendervulkan.hpp +index fa519db..4f0bff0 100644 +--- a/src/rendervulkan.hpp ++++ b/src/rendervulkan.hpp +@@ -161,7 +161,7 @@ public: + VkImageType imageType; + }; + +- bool BInit( uint32_t width, uint32_t height, uint32_t depth, uint32_t drmFormat, createFlags flags, wlr_dmabuf_attributes *pDMA = nullptr, uint32_t contentWidth = 0, uint32_t contentHeight = 0, CVulkanTexture *pExistingImageToReuseMemory = nullptr, gamescope::OwningRc pBackendFb = nullptr ); ++ bool BInit( uint32_t width, uint32_t height, uint32_t depth, uint32_t drmFormat, createFlags flags, wlr_dmabuf_attributes *pDMA = nullptr, uint32_t contentWidth = 0, uint32_t contentHeight = 0, CVulkanTexture *pExistingImageToReuseMemory = nullptr, gamescope::OwningRc pBackendFb = nullptr, std::shared_ptr pScanoutBuffer = nullptr ); + bool BInitFromSwapchain( VkImage image, uint32_t width, uint32_t height, VkFormat format ); + + uint32_t IncRef(); +@@ -211,9 +211,17 @@ public: + uint32_t queueFamily = VK_QUEUE_FAMILY_IGNORED; + + private: ++ bool BInitInternal( uint32_t width, uint32_t height, uint32_t depth, uint32_t drmFormat, createFlags flags, wlr_dmabuf_attributes *pDMA, uint32_t contentWidth, uint32_t contentHeight, CVulkanTexture *pExistingImageToReuseMemory, gamescope::OwningRc pBackendFb, std::shared_ptr pScanoutBuffer, bool bAllowExternalScanout ); ++ // Frees everything BInitInternal may have created, so a failed init can ++ // be retried. Also used by the destructor. ++ void ReleaseResources(); ++ + bool m_bInitialized = false; + bool m_bExternal = false; + bool m_bOutputImage = false; ++ // False for swapchain images: those are owned by the swapchain and must ++ // never be passed to vkDestroyImage. ++ bool m_bOwnsImage = false; + + uint32_t m_drmFormat = DRM_FORMAT_INVALID; + +@@ -251,6 +259,12 @@ private: + EStreamColorspace m_streamColorspace = k_EStreamColorspace_Unknown; + + struct wlr_dmabuf_attributes m_dmabuf = {}; ++ ++ // Set when the underlying memory was allocated by the backend (GBM on ++ // the DRM backend) and imported into Vulkan, rather than allocated by ++ // Vulkan. Keeps the backend allocation alive for the texture's lifetime; ++ // aliasing textures (eg. the partial-overlay output images) share it. ++ std::shared_ptr m_pScanoutBuffer; + }; + + struct vec2_t +@@ -788,6 +802,7 @@ static inline uint32_t div_roundup(uint32_t x, uint32_t y) + VK_FUNC(GetImageMemoryRequirements) \ + VK_FUNC(GetImageSubresourceLayout) \ + VK_FUNC(GetMemoryFdKHR) \ ++ VK_FUNC(GetMemoryFdPropertiesKHR) \ + VK_FUNC(GetQueryPoolResults) \ + VK_FUNC(GetSemaphoreCounterValue) \ + VK_FUNC(GetSwapchainImagesKHR) \ +diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp +index 2ff296b..2cb5eb5 100644 +--- a/src/steamcompmgr.cpp ++++ b/src/steamcompmgr.cpp +@@ -161,6 +161,7 @@ static lut3d_t g_tmpLut3d; + extern int g_nDynamicRefreshHz; + + bool g_bForceHDRSupportDebug = false; ++std::atomic g_bForceOutputImageRemake = { false }; + extern float g_flInternalDisplayBrightnessNits; + extern float g_flHDRItmSdrNits; + extern float g_flHDRItmTargetNits; +@@ -10255,13 +10256,21 @@ steamcompmgr_main(int argc, char **argv) + // Pick our width/height for this potential frame, regardless of how it might change later + // At some point we might even add proper locking so we get real updates atomically instead + // of whatever jumble of races the below might cause over a couple of frames ++ // Consume the remake request exactly once, before evaluating the other ++ // conditions: a concurrent request (eg. the drm_gbm_scanout convar ++ // callback on the Wayland thread) must never be cleared unseen, only ++ // exchanged out - a write racing past this point stays set for the ++ // next iteration. ++ const bool bForceOutputImageRemake = g_bForceOutputImageRemake.exchange( false ); ++ + if ( currentOutputWidth != g_nOutputWidth || + currentOutputHeight != g_nOutputHeight || + currentOutputRefresh != g_nOutputRefresh || + currentOutputRotation != g_uOutputRotation || + currentHDROutput != g_bOutputHDREnabled || + currentHDRCapable != bOutputHDRCapable || +- currentHDRForce != g_bForceHDRSupportDebug ) ++ currentHDRForce != g_bForceHDRSupportDebug || ++ bForceOutputImageRemake ) + { + if ( g_nXWaylandCount > 1 ) + { +diff --git a/src/steamcompmgr.hpp b/src/steamcompmgr.hpp +index c1d1ab0..fc7a521 100644 +--- a/src/steamcompmgr.hpp ++++ b/src/steamcompmgr.hpp +@@ -22,6 +22,7 @@ void steamcompmgr_main(int argc, char **argv); + #include "vblankmanager.hpp" + #include "mangoapp_control.h" + ++#include + #include + #include + #include +@@ -45,6 +46,10 @@ static const uint32_t g_zposMuraCorrection = 5; + extern bool g_bHDRItmEnable; + extern bool g_bForceHDRSupportDebug; + ++// Request a rebuild of the output images on the next steamcompmgr iteration, ++// eg. after toggling scanout buffer allocation strategy at runtime. ++extern std::atomic g_bForceOutputImageRemake; ++ + extern EStreamColorspace g_ForcedNV12ColorSpace; + + struct CursorBarrierInfo From d1758ac5ebd83e2af9bae6c91956c7a034dc6998 Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 18:18:09 +0200 Subject: [PATCH 03/26] feat: SteamOS conversion on NVIDIA with a patched gamescope (GBM scan-out) The conversion is offered on supported NVIDIA cards again; it builds and installs steamify-gamescope-nvidia and sets gamescope_drm_gbm_scanout=1. It and Gaming on NVIDIA exclude each other. --- CHANGELOG.md | 2 ++ TECHNICAL.md | 12 +++++++ lib/backend.sh | 11 +++++-- lib/gamescope-nvidia.sh | 71 +++++++++++++++++++++++++++++++++++++++++ lib/login-manager.sh | 3 ++ lib/menu.sh | 20 +++++++++--- lib/nvidia.sh | 6 ++-- steamify.sh | 2 +- ui/qml/AppState.qml | 11 +++++-- 9 files changed, 124 insertions(+), 14 deletions(-) create mode 100644 lib/gamescope-nvidia.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 35deee2..cbb8b2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ one per merged pull request. ## 2.11.2 - 2026-10-13 +- **feat: the SteamOS conversion is offered on NVIDIA PCs again (RTX 20 series or newer): it builds and installs a patched gamescope from [steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia) (GBM-allocated scan-out buffers, NVIDIA's corrupted gaming-mode picture, gamescope#2309; a few minutes to build) and sets `gamescope_drm_gbm_scanout=1` for the session (`lib/gamescope-nvidia.sh`). It and "Gaming on NVIDIA" exclude each other; single user mode works with either. Tested on an RTX 5080 (driver 615.78.08): Steam's gaming UI is clean with it and shows artifacts without. The package is pinned to one gamescope release: updating it is not automatic yet** + - **feat: "Gaming on NVIDIA" also keeps video memory over suspend (`NVreg_PreserveVideoMemoryAllocations=1` in `/etc/modprobe.d/90-steamify-nvidia.conf`, the initramfs is rebuilt), enables `nvidia-suspend`/`nvidia-resume`/`nvidia-hibernate`, and installs `lib32-nvidia-utils` and `lib32-libxkbcommon` (32-bit games, the 32-bit MangoHud preload) on a supported card; off removes only what Steamify added. Untested on hardware yet** ## 2.11.1 - 2026-10-02 diff --git a/TECHNICAL.md b/TECHNICAL.md index a94ee5f..ad212ee 100644 --- a/TECHNICAL.md +++ b/TECHNICAL.md @@ -238,6 +238,18 @@ no fix known). The kernel parameters `nvidia-drm.modeset=1`/`fbdev=1` and loadin window straight to the display. What does work on an RTX 5080: Steam's Big Picture (`steam -gamepadui`) as a normal window of the Plasma desktop session, smooth and clean. +Since 2.11.2 there is a second way: gamescope with GBM-allocated scan-out buffers (`lib/gamescope-nvidia.sh`). On an RTX 5080 +(driver 615.78.08, 3440x1440@175) Steam's gaming UI in gamescope's DRM session is clean with it and shows artifacts everywhere +without. The patch is nine commits of [farnoy/gamescope](https://github.com/farnoy/gamescope) (`nvidia-gbm-wayland`), kept in +[steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia) with its PKGBUILD; `gsn_install_package` clones +that repository, builds the package as the user (`makepkg -sf`) and installs it with `pacman -U --ask 4` (the package provides and +conflicts with `gamescope`). It is opt-in inside gamescope: `gamescope_drm_gbm_scanout=1` in +`~/.config/gamescope-session/environment` and `~/.config/environment.d/99-steamify-gamescope-nvidia.conf`. The SteamOS conversion +(`gaming_enable`) does this on a supported card (`nvidia_supported`), so on those PCs it is offered next to "Gaming on NVIDIA" +and the two exclude each other (`toggle_component`, `backend.sh`, `AppState.qml`); single user mode works with either. Turning the +conversion off removes the setting and keeps the package. The package is pinned to the gamescope release the patch was made for +(`UPSTREAM_VERSION` in that repository): pacman does not update it, and Steamify does not rebuild it yet. + So with an NVIDIA GPU (PCI vendor 0x10de, display class, its driver providing `nvidia_drm`: `nvidia_present`) the SteamOS conversion (`gaming`, and its options `boot`, `single`, `glyphs`) isn't offered, unless it is already on (so it can be turned off). `nvidia` ("Gaming on NVIDIA", `lib/nvidia.sh`) takes its place, hidden while the conversion is on (both would start diff --git a/lib/backend.sh b/lib/backend.sh index f205da8..30c9baa 100644 --- a/lib/backend.sh +++ b/lib/backend.sh @@ -147,10 +147,15 @@ backend_apply() { for id in "${want[@]}"; do [[ "$id" == "$c" ]] && WANTED[$c]=1; done done # The same rules as the menu's toggles. - # (Single user mode only needs the conversion where it is offered: not on NVIDIA PCs.) - [[ "${WANTED[single]:-0}" == 1 ]] && component_available gaming && WANTED[gaming]=1 + # (Single user mode only needs the conversion where it is offered: not on NVIDIA PCs, where it works without it.) + [[ "${WANTED[single]:-0}" == 1 ]] && component_available gaming && ! nvidia_present && WANTED[gaming]=1 + # On NVIDIA the conversion and "Gaming on NVIDIA" exclude each other: the one that is not on yet wins. + if nvidia_present && [[ "${WANTED[gaming]:-0}" == 1 && "${WANTED[nvidia]:-0}" == 1 ]]; then + if [[ "${CURRENT[gaming]:-0}" == 1 ]]; then WANTED[gaming]=0; WANTED[boot]=0; WANTED[silent]=0; WANTED[glyphs]=0 + else WANTED[nvidia]=0; WANTED[bigpicture]=0; WANTED[nvsilent]=0; fi + fi if component_available gaming; then - [[ "${WANTED[gaming]:-0}" == 0 ]] && { WANTED[single]=0; WANTED[boot]=0; } + [[ "${WANTED[gaming]:-0}" == 0 ]] && { nvidia_present || WANTED[single]=0; WANTED[boot]=0; } else WANTED[boot]=0 fi diff --git a/lib/gamescope-nvidia.sh b/lib/gamescope-nvidia.sh new file mode 100644 index 0000000..8819e31 --- /dev/null +++ b/lib/gamescope-nvidia.sh @@ -0,0 +1,71 @@ +#!/bin/bash +# gamescope's own gaming mode on NVIDIA: a patched gamescope that allocates its scan-out buffers with GBM, which cures +# the corrupted picture (https://github.com/ValveSoftware/gamescope/issues/2309). The patch and the build recipe live in +# https://github.com/theupriser/steamify-gamescope-nvidia; the package `steamify-gamescope-nvidia` is built here, on the PC, +# and replaces `gamescope` (it provides it). The patch is opt-in: gamescope reads `gamescope_drm_gbm_scanout=1` from its +# environment, which is set for the gaming session (gamescope-session's environment file, and environment.d). +# Used by the SteamOS conversion (`gaming_enable`/`gaming_disable`) on a supported NVIDIA card (`nvidia_supported`). +# Sourced by steamify.sh; not meant to be run on its own. + +GSN_PKG=steamify-gamescope-nvidia +GSN_REPO=${GSN_REPO:-https://github.com/theupriser/steamify-gamescope-nvidia.git} +GSN_ENV_LINE='gamescope_drm_gbm_scanout=1' +GSN_ENV_D="${GSN_ENV_D:-$HOME/.config/environment.d/99-steamify-gamescope-nvidia.conf}" +GSN_SESSION_ENV="${GSN_SESSION_ENV:-$HOME/.config/gamescope-session/environment}" + +gsn_package_installed() { pacman -Q "$GSN_PKG" >/dev/null 2>&1; } + +gsn_env_set() { [[ -f "$GSN_ENV_D" ]] && grep -qsx "$GSN_ENV_LINE" "$GSN_SESSION_ENV"; } + +gsn_status() { gsn_package_installed && gsn_env_set; } + +gsn_install_package() { + # Builds the package from the repo (makepkg runs as the user, never as root) and installs it. The build needs a few + # minutes: gamescope compiles from source. --ask 4 lets pacman replace the stock gamescope it conflicts with. + gsn_package_installed && return 0 + info "Building the patched gamescope for NVIDIA (a few minutes)..." + sudo pacman -S --needed --noconfirm base-devel git || { err "Installing the build tools failed."; return 1; } + local dir pkg + dir="$(mktemp -d)" || return 1 + if ! git clone --depth 1 "$GSN_REPO" "$dir/src"; then + err "Couldn't download $GSN_REPO." + rm -rf "$dir"; return 1 + fi + if ! (cd "$dir/src" && makepkg -sf --noconfirm --nocheck); then + err "Building the patched gamescope failed (see above). The stock gamescope stays." + rm -rf "$dir"; return 1 + fi + pkg="$(ls "$dir"/src/"$GSN_PKG"-*.pkg.tar.* 2>/dev/null | grep -v -- '-debug-' | head -1)" + if [[ -z "$pkg" ]] || ! sudo pacman -U --noconfirm --ask 4 "$pkg"; then + err "Installing the patched gamescope failed. The stock gamescope stays." + rm -rf "$dir"; return 1 + fi + rm -rf "$dir" + ok "Patched gamescope installed." +} + +gsn_env_enable() { + mkdir -p "$(dirname "$GSN_ENV_D")" "$(dirname "$GSN_SESSION_ENV")" + echo "$GSN_ENV_LINE" > "$GSN_ENV_D" + touch "$GSN_SESSION_ENV" + grep -qsx "$GSN_ENV_LINE" "$GSN_SESSION_ENV" || echo "$GSN_ENV_LINE" >> "$GSN_SESSION_ENV" +} + +gsn_env_disable() { + rm -f "$GSN_ENV_D" + [[ -f "$GSN_SESSION_ENV" ]] && sed -i "/^${GSN_ENV_LINE}\$/d" "$GSN_SESSION_ENV" + return 0 +} + +gsn_enable() { + # Only on a supported NVIDIA card; elsewhere the stock gamescope is right. + nvidia_supported || return 0 + gsn_install_package || return 1 + gsn_env_enable + ok "gamescope draws NVIDIA's picture through GBM (gamescope_drm_gbm_scanout=1) from the next gaming mode start." +} + +gsn_disable() { + # The setting goes; the patched package stays, like the other packages (steam, gamescope-session-cachyos). + gsn_env_disable +} diff --git a/lib/login-manager.sh b/lib/login-manager.sh index 7cef57f..2781f71 100644 --- a/lib/login-manager.sh +++ b/lib/login-manager.sh @@ -94,6 +94,8 @@ gaming_enable() { # LOGIN_MANAGER (sddm with single user, else plasmalogin) is set by the # menu. Re-running with the other value switches over cleanly. install_required_packages || return 1 + # NVIDIA: gamescope's picture is corrupted unless it is the patched one (no-op elsewhere). + gsn_enable || return 1 case "$LOGIN_MANAGER" in sddm) switch_to_sddm || return 1 @@ -122,6 +124,7 @@ gaming_disable() { switch_to_plasmalogin remove_desktop_shortcut steam_disable + gsn_disable krevert gaming os_name_disable ok "The PC boots to the normal login screen again (from the next boot)." diff --git a/lib/menu.sh b/lib/menu.sh index 22824ae..2d9103e 100644 --- a/lib/menu.sh +++ b/lib/menu.sh @@ -57,9 +57,10 @@ declare -A CURRENT WANTED component_available() { case "$1" in - # gamescope's own session is broken on NVIDIA: the conversion is replaced by "Gaming on NVIDIA" there (shown - # anyway when it's already on, so it can be turned off). - gaming|boot|silent|glyphs) ! nvidia_present || gaming_status ;; + # gamescope's own session shows a corrupted picture on NVIDIA unless it is the patched one (lib/gamescope-nvidia.sh, + # installed with the conversion on a supported card); "Gaming on NVIDIA" is the alternative there. Older NVIDIA + # cards only get the alternative (the conversion is shown anyway when it's already on, so it can be turned off). + gaming|boot|silent|glyphs) ! nvidia_present || gaming_status || nvidia_supported ;; nvidia) nvidia_available ;; bigpicture|nvsilent) bigpicture_available ;; machine|poweroff) machine_available ;; @@ -297,8 +298,8 @@ toggle_component() { WANTED[$c]=$(( 1 - WANTED[$c] )) # Single user mode only makes sense on top of the SteamOS conversion. # (On NVIDIA the conversion isn't offered: single user mode logs in by itself, see lib/single-user.sh.) - if [[ "$c" == single && "${WANTED[single]}" == 1 ]] && component_available gaming; then WANTED[gaming]=1; fi - if [[ "$c" == gaming && "${WANTED[gaming]}" == 0 ]]; then WANTED[single]=0; WANTED[boot]=0; fi + if [[ "$c" == single && "${WANTED[single]}" == 1 ]] && component_available gaming && ! nvidia_present; then WANTED[gaming]=1; fi + if [[ "$c" == gaming && "${WANTED[gaming]}" == 0 ]]; then nvidia_present || WANTED[single]=0; WANTED[boot]=0; fi # Where to boot to is part of the conversion, too. if [[ "$c" == boot && "${WANTED[boot]}" == 1 ]]; then WANTED[gaming]=1; fi # Big Picture is opt-out: ticked along with "Gaming on NVIDIA". @@ -310,6 +311,15 @@ toggle_component() { if [[ "$c" == gaming && "${WANTED[gaming]}" == 0 ]]; then WANTED[silent]=0; WANTED[glyphs]=0; fi if [[ "$c" == silent && "${WANTED[silent]}" == 1 ]]; then WANTED[gaming]=1; fi if [[ "$c" == glyphs && "${WANTED[glyphs]}" == 1 ]]; then WANTED[gaming]=1; fi + # On NVIDIA the SteamOS conversion and "Gaming on NVIDIA" exclude each other (both would start Steam at login); + # single user mode works with either. + if nvidia_present; then + if [[ "$c" == nvidia && "${WANTED[nvidia]}" == 1 ]]; then + WANTED[gaming]=0; WANTED[boot]=0; WANTED[silent]=0; WANTED[glyphs]=0 + elif [[ "$c" =~ ^(gaming|boot|silent|glyphs)$ && "${WANTED[$c]}" == 1 && "${WANTED[gaming]}" == 1 ]]; then + WANTED[nvidia]=0; WANTED[bigpicture]=0; WANTED[nvsilent]=0 + fi + fi # The power-off fix is opt-out: ticked along with Steam Machine support. if [[ "$c" == machine ]]; then WANTED[poweroff]=${WANTED[machine]}; fi if [[ "$c" == poweroff && "${WANTED[poweroff]}" == 1 ]]; then WANTED[machine]=1; fi diff --git a/lib/nvidia.sh b/lib/nvidia.sh index 28eed6c..a09f792 100644 --- a/lib/nvidia.sh +++ b/lib/nvidia.sh @@ -37,9 +37,9 @@ nvidia_present() { return 1 } -# Shown on NVIDIA PCs, unless the SteamOS conversion is already on there (it -# has to be turned off first: both would start Steam at login). -nvidia_available() { nvidia_present && ! gaming_status 2>/dev/null; } +# Shown on NVIDIA PCs. It and the SteamOS conversion exclude each other (both +# would start Steam at login): the menu unticks one when the other is ticked. +nvidia_available() { nvidia_present; } bigpicture_available() { nvidia_available; } nvidia_status() { diff --git a/steamify.sh b/steamify.sh index a87cfdf..cf39a0d 100755 --- a/steamify.sh +++ b/steamify.sh @@ -19,7 +19,7 @@ VERSION=2.11.2 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -for lib in common state packages login-manager single-user steam-desktop steam-machine fremont-poweroff vram-booster hdmi-refresh nvidia controllers cec boot-session vapor-theme steamos-extras bios desktop-shortcut wizard-shortcut steam-game update-notifier first-login menu backend; do +for lib in common state packages login-manager single-user steam-desktop steam-machine fremont-poweroff vram-booster hdmi-refresh nvidia gamescope-nvidia controllers cec boot-session vapor-theme steamos-extras bios desktop-shortcut wizard-shortcut steam-game update-notifier first-login menu backend; do # shellcheck source=/dev/null source "$SCRIPT_DIR/lib/$lib.sh" done diff --git a/ui/qml/AppState.qml b/ui/qml/AppState.qml index 6148d9c..b15c5ff 100644 --- a/ui/qml/AppState.qml +++ b/ui/qml/AppState.qml @@ -78,14 +78,21 @@ Item { w[id] = !w[id]; // The same rules as the terminal menu (toggle_component). var hasGaming = items.some(function (i) { return i.id === "gaming"; }); - if (id === "gaming" && !w.gaming) { w.single = false; w.silent = false; w.glyphs = false; } - if (id === "single" && w.single && hasGaming) w.gaming = true; + var hasNvidia = items.some(function (i) { return i.id === "nvidia"; }); + // Single user mode works without the conversion on NVIDIA PCs. + if (id === "gaming" && !w.gaming) { if (!hasNvidia) w.single = false; w.silent = false; w.glyphs = false; } + if (id === "single" && w.single && hasGaming && !hasNvidia) w.gaming = true; if (id === "nvidia") w.bigpicture = w.nvidia; if (id === "bigpicture" && w.bigpicture) { w.nvidia = true; w.nvsilent = false; } if (id === "nvsilent" && w.nvsilent) { w.nvidia = true; w.bigpicture = false; } if (id === "nvidia" && !w.nvidia) w.nvsilent = false; if (id === "silent" && w.silent) w.gaming = true; if (id === "glyphs" && w.glyphs) w.gaming = true; + // On NVIDIA the conversion and "Gaming on NVIDIA" exclude each other (both would start Steam at login). + if (hasGaming && hasNvidia) { + if (id === "nvidia" && w.nvidia) { w.gaming = false; w.silent = false; w.glyphs = false; } + else if ((id === "gaming" || id === "silent" || id === "glyphs") && w[id] && w.gaming) { w.nvidia = false; w.bigpicture = false; w.nvsilent = false; } + } if (id === "machine") w.poweroff = w.machine; if (id === "poweroff" && w.poweroff) w.machine = true; if (id === "machine" && !w.machine) w.kpin = false; From af182538dc02eda21a8bb2ef745492a86e72e493 Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 18:18:27 +0200 Subject: [PATCH 04/26] docs: NVIDIA section of TECHNICAL.md follows the patched gamescope --- TECHNICAL.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/TECHNICAL.md b/TECHNICAL.md index ad212ee..03c1469 100644 --- a/TECHNICAL.md +++ b/TECHNICAL.md @@ -251,8 +251,9 @@ conversion off removes the setting and keeps the package. The package is pinned (`UPSTREAM_VERSION` in that repository): pacman does not update it, and Steamify does not rebuild it yet. So with an NVIDIA GPU (PCI vendor 0x10de, display class, its driver providing `nvidia_drm`: `nvidia_present`) the SteamOS -conversion (`gaming`, and its options `boot`, `single`, `glyphs`) isn't offered, unless it is already on (so it can be turned -off). `nvidia` ("Gaming on NVIDIA", `lib/nvidia.sh`) takes its place, hidden while the conversion is on (both would start +conversion (`gaming`, and its options `boot`, `single`, `glyphs`) is only offered on a supported card (RTX 20 series or newer, +`nvidia_supported`) with the patched gamescope described below, or when it is already on (so it can be turned off). +`nvidia` ("Gaming on NVIDIA", `lib/nvidia.sh`) is the alternative, and excludes the conversion (both would start Steam at login): it installs `steam` when missing (recorded in state `nvidia`, removed again only then) and enables the user unit `steamify-steam-autostart.service` (`services/`, `ExecStart=/usr/bin/steam @ARGS@`, Plasma only). Its sub-option `bigpicture` ("Steam starts in Big Picture", ticked along with it) rewrites the unit with `-gamepadui` and sets @@ -584,6 +585,7 @@ immediately, which can turn into a loop - see | `lib/update-notifier.sh` | Update notifications: the notifier from `patches/` and its user timer | | `lib/first-login.sh` | `--defaults` without a session (the Steam Machine ISO's installer): the one-time first-login step that sets up single user's launcher on Plasma's new layout and opens the app | | `lib/controllers.sh` | Extended controller support: Xbox wireless dongle (xone) and Xbox Bluetooth (xpadneo) from the CachyOS repo | +| `lib/gamescope-nvidia.sh` | gamescope on NVIDIA: builds and installs the patched gamescope (GBM scan-out) from steamify-gamescope-nvidia and sets `gamescope_drm_gbm_scanout=1` for the SteamOS conversion | | `lib/nvidia.sh` | Gaming on NVIDIA: Steam on the desktop, started at login, optionally in Big Picture (replaces the SteamOS conversion there) | | `lib/vram-booster.sh` | VRAM booster (`dmemcg-booster`, `plasma-foreground-booster`) | | `services/` | The systemd units the scripts install (`service_file`, `@KEY@` placeholders); see its README | From 358efa05f2916012c9a060b4cc8e4b07b9fbdd1e Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 18:19:21 +0200 Subject: [PATCH 05/26] fix: on NVIDIA the SteamOS conversion is a choice, Gaming on NVIDIA stays preselected; supported cards are GTX 16 / RTX 20 and newer --- CHANGELOG.md | 2 +- TECHNICAL.md | 2 +- lib/gamescope-nvidia.sh | 3 ++- lib/menu.sh | 4 ++++ lib/nvidia.sh | 2 +- 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cbb8b2e..e11692a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ one per merged pull request. ## 2.11.2 - 2026-10-13 -- **feat: the SteamOS conversion is offered on NVIDIA PCs again (RTX 20 series or newer): it builds and installs a patched gamescope from [steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia) (GBM-allocated scan-out buffers, NVIDIA's corrupted gaming-mode picture, gamescope#2309; a few minutes to build) and sets `gamescope_drm_gbm_scanout=1` for the session (`lib/gamescope-nvidia.sh`). It and "Gaming on NVIDIA" exclude each other; single user mode works with either. Tested on an RTX 5080 (driver 615.78.08): Steam's gaming UI is clean with it and shows artifacts without. The package is pinned to one gamescope release: updating it is not automatic yet** +- **feat: the SteamOS conversion is offered on NVIDIA PCs again (GTX 16 / RTX 20 series or newer: Turing and later, the cards NVIDIA's open kernel driver supports): it builds and installs a patched gamescope from [steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia) (GBM-allocated scan-out buffers, NVIDIA's corrupted gaming-mode picture, gamescope#2309; a few minutes to build) and sets `gamescope_drm_gbm_scanout=1` for the session (`lib/gamescope-nvidia.sh`). It and "Gaming on NVIDIA" exclude each other; single user mode works with either. Tested on an RTX 5080 (driver 615.78.08): Steam's gaming UI is clean with it and shows artifacts without. The package is pinned to one gamescope release: updating it is not automatic yet** - **feat: "Gaming on NVIDIA" also keeps video memory over suspend (`NVreg_PreserveVideoMemoryAllocations=1` in `/etc/modprobe.d/90-steamify-nvidia.conf`, the initramfs is rebuilt), enables `nvidia-suspend`/`nvidia-resume`/`nvidia-hibernate`, and installs `lib32-nvidia-utils` and `lib32-libxkbcommon` (32-bit games, the 32-bit MangoHud preload) on a supported card; off removes only what Steamify added. Untested on hardware yet** diff --git a/TECHNICAL.md b/TECHNICAL.md index 03c1469..8d3094b 100644 --- a/TECHNICAL.md +++ b/TECHNICAL.md @@ -251,7 +251,7 @@ conversion off removes the setting and keeps the package. The package is pinned (`UPSTREAM_VERSION` in that repository): pacman does not update it, and Steamify does not rebuild it yet. So with an NVIDIA GPU (PCI vendor 0x10de, display class, its driver providing `nvidia_drm`: `nvidia_present`) the SteamOS -conversion (`gaming`, and its options `boot`, `single`, `glyphs`) is only offered on a supported card (RTX 20 series or newer, +conversion (`gaming`, and its options `boot`, `single`, `glyphs`) is only offered on a supported card (GTX 16 / RTX 20 series or newer, Turing and later, `nvidia_supported`) with the patched gamescope described below, or when it is already on (so it can be turned off). `nvidia` ("Gaming on NVIDIA", `lib/nvidia.sh`) is the alternative, and excludes the conversion (both would start Steam at login): it installs `steam` when missing (recorded in state `nvidia`, removed again only then) and enables the user diff --git a/lib/gamescope-nvidia.sh b/lib/gamescope-nvidia.sh index 8819e31..6904112 100644 --- a/lib/gamescope-nvidia.sh +++ b/lib/gamescope-nvidia.sh @@ -4,7 +4,8 @@ # https://github.com/theupriser/steamify-gamescope-nvidia; the package `steamify-gamescope-nvidia` is built here, on the PC, # and replaces `gamescope` (it provides it). The patch is opt-in: gamescope reads `gamescope_drm_gbm_scanout=1` from its # environment, which is set for the gaming session (gamescope-session's environment file, and environment.d). -# Used by the SteamOS conversion (`gaming_enable`/`gaming_disable`) on a supported NVIDIA card (`nvidia_supported`). +# Used by the SteamOS conversion (`gaming_enable`/`gaming_disable`) on a supported NVIDIA card (`nvidia_supported`): +# GTX 16 / RTX 20 series or newer (Turing and later, what NVIDIA's open kernel driver supports). # Sourced by steamify.sh; not meant to be run on its own. GSN_PKG=steamify-gamescope-nvidia diff --git a/lib/menu.sh b/lib/menu.sh index 2d9103e..dc5e2b9 100644 --- a/lib/menu.sh +++ b/lib/menu.sh @@ -206,6 +206,8 @@ detect_components() { component_available "$c" && component_selectable "$c" && ! is_action "$c" && [[ " ${NO_PRESELECT[*]} " != *" $c "* ]] && WANTED[$c]=1 done + # On NVIDIA "Gaming on NVIDIA" is the default; the conversion (a patched gamescope, built here) is a choice. + nvidia_present && WANTED[gaming]=0 WANTED[glyphs]=0 machine_available && WANTED[cec]=1 fi } @@ -284,6 +286,8 @@ defaults_list() { sel=false; component_selectable "$c" && sel=true on=false [[ "$sel" == true && " ${NO_PRESELECT[*]} " != *" $c "* ]] && on=true + # (On NVIDIA the conversion is a choice: "Gaming on NVIDIA" is preselected, see show_menu's first run.) + [[ "$c" == gaming || "$c" == glyphs ]] && nvidia_present && on=false [[ "$c" == cec ]] && machine_available && on=true items+="${items:+,}{\"id\":$(json_str "$c"),\"label\":$(json_str "${LABEL[$c]%%:*}")" items+=",\"hint\":$(json_str "$( [[ "${LABEL[$c]}" == *:* ]] && echo "${LABEL[$c]#*: }")")" diff --git a/lib/nvidia.sh b/lib/nvidia.sh index a09f792..348ee4c 100644 --- a/lib/nvidia.sh +++ b/lib/nvidia.sh @@ -125,7 +125,7 @@ nvsilent_disable() { nvidia_supported() { # A supported NVIDIA GPU: PCI vendor 0x10de, display class, its kernel - # driver installed, and not older than the RTX 20 series, decided like the + # driver installed, and not older than Turing (GTX 16 / RTX 20 series: the cards NVIDIA's open kernel driver supports), decided like the # VRAM booster does (vram_nvidia_legacy_id: chwd's legacy card lists, every # other card runs NVIDIA's open modules). Older cards are left alone. local d From bad9a6bf4417c81c5f9abf20fae687f66079d96d Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 18:24:54 +0200 Subject: [PATCH 06/26] feat: on a supported NVIDIA card the SteamOS conversion replaces Gaming on NVIDIA The conversion also sets up what Gaming on NVIDIA did there (kernel parameters, early modules, suspend memory, 32-bit libraries). Gaming on NVIDIA is only offered on older NVIDIA cards, or while it is on. --- CHANGELOG.md | 2 +- TECHNICAL.md | 12 +++++++----- lib/gamescope-nvidia.sh | 10 +++++++++- lib/menu.sh | 4 ---- lib/nvidia.sh | 17 ++++++++++++----- 5 files changed, 29 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e11692a..5673757 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ one per merged pull request. ## 2.11.2 - 2026-10-13 -- **feat: the SteamOS conversion is offered on NVIDIA PCs again (GTX 16 / RTX 20 series or newer: Turing and later, the cards NVIDIA's open kernel driver supports): it builds and installs a patched gamescope from [steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia) (GBM-allocated scan-out buffers, NVIDIA's corrupted gaming-mode picture, gamescope#2309; a few minutes to build) and sets `gamescope_drm_gbm_scanout=1` for the session (`lib/gamescope-nvidia.sh`). It and "Gaming on NVIDIA" exclude each other; single user mode works with either. Tested on an RTX 5080 (driver 615.78.08): Steam's gaming UI is clean with it and shows artifacts without. The package is pinned to one gamescope release: updating it is not automatic yet** +- **feat: the SteamOS conversion is offered on NVIDIA PCs again (GTX 16 / RTX 20 series or newer: Turing and later, the cards NVIDIA's open kernel driver supports): it builds and installs a patched gamescope from [steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia) (GBM-allocated scan-out buffers, NVIDIA's corrupted gaming-mode picture, gamescope#2309; a few minutes to build) and sets `gamescope_drm_gbm_scanout=1` for the session (`lib/gamescope-nvidia.sh`). On those cards it replaces "Gaming on NVIDIA" (kernel parameters, early modules, suspend memory and the 32-bit libraries come with it); "Gaming on NVIDIA" is only offered on older NVIDIA cards, or while it is on (turn it off or swap it for the conversion; the two exclude each other); single user mode works with either. Tested on an RTX 5080 (driver 615.78.08): Steam's gaming UI is clean with it and shows artifacts without. The package is pinned to one gamescope release: updating it is not automatic yet** - **feat: "Gaming on NVIDIA" also keeps video memory over suspend (`NVreg_PreserveVideoMemoryAllocations=1` in `/etc/modprobe.d/90-steamify-nvidia.conf`, the initramfs is rebuilt), enables `nvidia-suspend`/`nvidia-resume`/`nvidia-hibernate`, and installs `lib32-nvidia-utils` and `lib32-libxkbcommon` (32-bit games, the 32-bit MangoHud preload) on a supported card; off removes only what Steamify added. Untested on hardware yet** diff --git a/TECHNICAL.md b/TECHNICAL.md index 8d3094b..c3e52f9 100644 --- a/TECHNICAL.md +++ b/TECHNICAL.md @@ -245,16 +245,18 @@ without. The patch is nine commits of [farnoy/gamescope](https://github.com/farn that repository, builds the package as the user (`makepkg -sf`) and installs it with `pacman -U --ask 4` (the package provides and conflicts with `gamescope`). It is opt-in inside gamescope: `gamescope_drm_gbm_scanout=1` in `~/.config/gamescope-session/environment` and `~/.config/environment.d/99-steamify-gamescope-nvidia.conf`. The SteamOS conversion -(`gaming_enable`) does this on a supported card (`nvidia_supported`), so on those PCs it is offered next to "Gaming on NVIDIA" -and the two exclude each other (`toggle_component`, `backend.sh`, `AppState.qml`); single user mode works with either. Turning the -conversion off removes the setting and keeps the package. The package is pinned to the gamescope release the patch was made for +(`gaming_enable`) does this on a supported card (`nvidia_supported`), together with what "Gaming on NVIDIA" sets up there (the kernel +parameters, the early modules, suspend memory, the 32-bit libraries: `nvidia_kernel_enable`, `nvidia_extras_enable`). So on a +supported card the conversion replaces "Gaming on NVIDIA": that one is only offered on older NVIDIA cards, or while it is already on +(to turn it off, or swap it for the conversion; the two exclude each other: `toggle_component`, `backend.sh`, `AppState.qml`). +Single user mode works with either. Turning the conversion off removes the setting and those settings, and keeps the packages. The package is pinned to the gamescope release the patch was made for (`UPSTREAM_VERSION` in that repository): pacman does not update it, and Steamify does not rebuild it yet. So with an NVIDIA GPU (PCI vendor 0x10de, display class, its driver providing `nvidia_drm`: `nvidia_present`) the SteamOS conversion (`gaming`, and its options `boot`, `single`, `glyphs`) is only offered on a supported card (GTX 16 / RTX 20 series or newer, Turing and later, `nvidia_supported`) with the patched gamescope described below, or when it is already on (so it can be turned off). -`nvidia` ("Gaming on NVIDIA", `lib/nvidia.sh`) is the alternative, and excludes the conversion (both would start -Steam at login): it installs `steam` when missing (recorded in state `nvidia`, removed again only then) and enables the user +`nvidia` ("Gaming on NVIDIA", `lib/nvidia.sh`) is for older NVIDIA cards (and for PCs where it is already on), and excludes the +conversion (both would start Steam at login): it installs `steam` when missing (recorded in state `nvidia`, removed again only then) and enables the user unit `steamify-steam-autostart.service` (`services/`, `ExecStart=/usr/bin/steam @ARGS@`, Plasma only). Its sub-option `bigpicture` ("Steam starts in Big Picture", ticked along with it) rewrites the unit with `-gamepadui` and sets `ksmserverrc [General] loginMode=emptySession` (`kset`, undone with `krevert bigpicture`), so windows of the last session diff --git a/lib/gamescope-nvidia.sh b/lib/gamescope-nvidia.sh index 6904112..d0ceaab 100644 --- a/lib/gamescope-nvidia.sh +++ b/lib/gamescope-nvidia.sh @@ -61,12 +61,20 @@ gsn_env_disable() { gsn_enable() { # Only on a supported NVIDIA card; elsewhere the stock gamescope is right. nvidia_supported || return 0 + # What NVIDIA's DRM stack wants (lib/nvidia.sh): modeset/fbdev on the kernel command line, the modules in the + # initramfs, video memory kept over suspend, the 32-bit libraries. Takes effect at the next boot, like the session. + nvidia_kernel_enable || return 1 + nvidia_extras_enable || return 1 gsn_install_package || return 1 gsn_env_enable ok "gamescope draws NVIDIA's picture through GBM (gamescope_drm_gbm_scanout=1) from the next gaming mode start." } gsn_disable() { - # The setting goes; the patched package stays, like the other packages (steam, gamescope-session-cachyos). + # The setting goes, and what nvidia_*_enable added; the packages stay (patched gamescope, 32-bit libraries), like + # the other packages of the conversion (steam, gamescope-session-cachyos). gsn_env_disable + nvidia_supported || return 0 + nvidia_extras_disable + nvidia_kernel_disable } diff --git a/lib/menu.sh b/lib/menu.sh index dc5e2b9..2d9103e 100644 --- a/lib/menu.sh +++ b/lib/menu.sh @@ -206,8 +206,6 @@ detect_components() { component_available "$c" && component_selectable "$c" && ! is_action "$c" && [[ " ${NO_PRESELECT[*]} " != *" $c "* ]] && WANTED[$c]=1 done - # On NVIDIA "Gaming on NVIDIA" is the default; the conversion (a patched gamescope, built here) is a choice. - nvidia_present && WANTED[gaming]=0 WANTED[glyphs]=0 machine_available && WANTED[cec]=1 fi } @@ -286,8 +284,6 @@ defaults_list() { sel=false; component_selectable "$c" && sel=true on=false [[ "$sel" == true && " ${NO_PRESELECT[*]} " != *" $c "* ]] && on=true - # (On NVIDIA the conversion is a choice: "Gaming on NVIDIA" is preselected, see show_menu's first run.) - [[ "$c" == gaming || "$c" == glyphs ]] && nvidia_present && on=false [[ "$c" == cec ]] && machine_available && on=true items+="${items:+,}{\"id\":$(json_str "$c"),\"label\":$(json_str "${LABEL[$c]%%:*}")" items+=",\"hint\":$(json_str "$( [[ "${LABEL[$c]}" == *:* ]] && echo "${LABEL[$c]#*: }")")" diff --git a/lib/nvidia.sh b/lib/nvidia.sh index 348ee4c..c92fb7e 100644 --- a/lib/nvidia.sh +++ b/lib/nvidia.sh @@ -37,9 +37,11 @@ nvidia_present() { return 1 } -# Shown on NVIDIA PCs. It and the SteamOS conversion exclude each other (both -# would start Steam at login): the menu unticks one when the other is ticked. -nvidia_available() { nvidia_present; } +# The SteamOS conversion with the patched gamescope (lib/gamescope-nvidia.sh) replaces this on a supported card, so +# this is for older NVIDIA cards, and for a PC where it is already on (so it can be turned off, or swapped for the +# conversion). It and the conversion exclude each other (both would start Steam at login): the menu unticks one when +# the other is ticked. +nvidia_available() { nvidia_present && { ! nvidia_supported || nvidia_status; }; } bigpicture_available() { nvidia_available; } nvidia_status() { @@ -76,14 +78,19 @@ nvidia_disable() { user_systemctl disable --now "$NVIDIA_UNIT" >/dev/null 2>&1 rm -f "$unit" user_systemctl daemon-reload - nvidia_extras_disable + # Swapped for the SteamOS conversion (turned on first, in the same run): it needs the same settings, they stay. + gaming_status 2>/dev/null || nvidia_extras_disable pkgs="$(state_get nvidia installed_pkgs)" + if gaming_status 2>/dev/null; then + local p; pkgs=" $pkgs " + for p in $NVIDIA_LIB32_PKGS; do pkgs="${pkgs// $p / }"; done + fi # Only what Steamify installed; games and the Steam folder stay. # shellcheck disable=SC2086 # a list of package names [[ -n "$pkgs" ]] && sudo pacman -Rns --noconfirm $pkgs >/dev/null 2>&1 state_clear nvidia krevert bigpicture - nvidia_kernel_disable + gaming_status 2>/dev/null || nvidia_kernel_disable ok "Steam no longer starts at login." } From 2ae3c4f4b3daf4adbe4bfdf4a6a343c9fdec2497 Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 18:27:13 +0200 Subject: [PATCH 07/26] feat: Gaming on NVIDIA is not offered any more, the SteamOS conversion covers NVIDIA PCs The conversion installs the patched gamescope on every NVIDIA PC and sets up the kernel parameters, suspend memory and 32-bit libraries on a supported card; it turns off an existing Gaming on NVIDIA. --- CHANGELOG.md | 2 +- TECHNICAL.md | 21 ++++++++++----------- lib/backend.sh | 10 ++-------- lib/gamescope-nvidia.sh | 16 ++++++++++------ lib/menu.sh | 23 +++++------------------ lib/nvidia.sh | 20 +++++++++++++++----- ui/qml/AppState.qml | 11 ++--------- 7 files changed, 45 insertions(+), 58 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5673757..d3f2209 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ one per merged pull request. ## 2.11.2 - 2026-10-13 -- **feat: the SteamOS conversion is offered on NVIDIA PCs again (GTX 16 / RTX 20 series or newer: Turing and later, the cards NVIDIA's open kernel driver supports): it builds and installs a patched gamescope from [steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia) (GBM-allocated scan-out buffers, NVIDIA's corrupted gaming-mode picture, gamescope#2309; a few minutes to build) and sets `gamescope_drm_gbm_scanout=1` for the session (`lib/gamescope-nvidia.sh`). On those cards it replaces "Gaming on NVIDIA" (kernel parameters, early modules, suspend memory and the 32-bit libraries come with it); "Gaming on NVIDIA" is only offered on older NVIDIA cards, or while it is on (turn it off or swap it for the conversion; the two exclude each other); single user mode works with either. Tested on an RTX 5080 (driver 615.78.08): Steam's gaming UI is clean with it and shows artifacts without. The package is pinned to one gamescope release: updating it is not automatic yet** +- **feat: the SteamOS conversion is offered on NVIDIA PCs again (GTX 16 / RTX 20 series or newer: Turing and later, the cards NVIDIA's open kernel driver supports): it builds and installs a patched gamescope from [steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia) (GBM-allocated scan-out buffers, NVIDIA's corrupted gaming-mode picture, gamescope#2309; a few minutes to build) and sets `gamescope_drm_gbm_scanout=1` for the session (`lib/gamescope-nvidia.sh`). It replaces "Gaming on NVIDIA", which is not offered any more (the kernel parameters, early modules, suspend memory and the 32-bit libraries come with the conversion on a supported card; a PC that had "Gaming on NVIDIA" on has it turned off when the conversion is turned on). Tested on an RTX 5080 (driver 615.78.08): Steam's gaming UI is clean with it and shows artifacts without. The package is pinned to one gamescope release: updating it is not automatic yet** - **feat: "Gaming on NVIDIA" also keeps video memory over suspend (`NVreg_PreserveVideoMemoryAllocations=1` in `/etc/modprobe.d/90-steamify-nvidia.conf`, the initramfs is rebuilt), enables `nvidia-suspend`/`nvidia-resume`/`nvidia-hibernate`, and installs `lib32-nvidia-utils` and `lib32-libxkbcommon` (32-bit games, the 32-bit MangoHud preload) on a supported card; off removes only what Steamify added. Untested on hardware yet** diff --git a/TECHNICAL.md b/TECHNICAL.md index c3e52f9..3ebe88a 100644 --- a/TECHNICAL.md +++ b/TECHNICAL.md @@ -245,18 +245,17 @@ without. The patch is nine commits of [farnoy/gamescope](https://github.com/farn that repository, builds the package as the user (`makepkg -sf`) and installs it with `pacman -U --ask 4` (the package provides and conflicts with `gamescope`). It is opt-in inside gamescope: `gamescope_drm_gbm_scanout=1` in `~/.config/gamescope-session/environment` and `~/.config/environment.d/99-steamify-gamescope-nvidia.conf`. The SteamOS conversion -(`gaming_enable`) does this on a supported card (`nvidia_supported`), together with what "Gaming on NVIDIA" sets up there (the kernel -parameters, the early modules, suspend memory, the 32-bit libraries: `nvidia_kernel_enable`, `nvidia_extras_enable`). So on a -supported card the conversion replaces "Gaming on NVIDIA": that one is only offered on older NVIDIA cards, or while it is already on -(to turn it off, or swap it for the conversion; the two exclude each other: `toggle_component`, `backend.sh`, `AppState.qml`). -Single user mode works with either. Turning the conversion off removes the setting and those settings, and keeps the packages. The package is pinned to the gamescope release the patch was made for -(`UPSTREAM_VERSION` in that repository): pacman does not update it, and Steamify does not rebuild it yet. +(`gaming_enable`) does this on every NVIDIA PC (`nvidia_present`: PCI vendor 0x10de, display class, its driver providing +`nvidia_drm`), together with what "Gaming on NVIDIA" set up (on a supported card, `nvidia_supported`: GTX 16 / RTX 20 series or +newer, Turing and later): the kernel parameters, the early modules, suspend memory, the 32-bit libraries (`nvidia_kernel_enable`, +`nvidia_extras_enable`). So the SteamOS conversion is the one gaming option on NVIDIA now, and "Gaming on NVIDIA" (below) is not +offered any more (`nvidia_available`); a PC that had it on keeps it until the conversion is turned on, which turns it off +(`nvidia_swap_out`). Turning the conversion off removes the setting and those settings, and keeps the packages. The package is +pinned to the gamescope release the patch was made for (`UPSTREAM_VERSION` in that repository): pacman does not update it, and +Steamify does not rebuild it yet. Tested on an RTX 5080 only. -So with an NVIDIA GPU (PCI vendor 0x10de, display class, its driver providing `nvidia_drm`: `nvidia_present`) the SteamOS -conversion (`gaming`, and its options `boot`, `single`, `glyphs`) is only offered on a supported card (GTX 16 / RTX 20 series or newer, Turing and later, -`nvidia_supported`) with the patched gamescope described below, or when it is already on (so it can be turned off). -`nvidia` ("Gaming on NVIDIA", `lib/nvidia.sh`) is for older NVIDIA cards (and for PCs where it is already on), and excludes the -conversion (both would start Steam at login): it installs `steam` when missing (recorded in state `nvidia`, removed again only then) and enables the user +Before 2.11.2, with an NVIDIA GPU the SteamOS conversion (`gaming`, and its options `boot`, `single`, `glyphs`) wasn't offered, unless +it was already on. `nvidia` ("Gaming on NVIDIA", `lib/nvidia.sh`) took its place (both would start Steam at login): it installs `steam` when missing (recorded in state `nvidia`, removed again only then) and enables the user unit `steamify-steam-autostart.service` (`services/`, `ExecStart=/usr/bin/steam @ARGS@`, Plasma only). Its sub-option `bigpicture` ("Steam starts in Big Picture", ticked along with it) rewrites the unit with `-gamepadui` and sets `ksmserverrc [General] loginMode=emptySession` (`kset`, undone with `krevert bigpicture`), so windows of the last session diff --git a/lib/backend.sh b/lib/backend.sh index 30c9baa..9d523eb 100644 --- a/lib/backend.sh +++ b/lib/backend.sh @@ -147,15 +147,9 @@ backend_apply() { for id in "${want[@]}"; do [[ "$id" == "$c" ]] && WANTED[$c]=1; done done # The same rules as the menu's toggles. - # (Single user mode only needs the conversion where it is offered: not on NVIDIA PCs, where it works without it.) - [[ "${WANTED[single]:-0}" == 1 ]] && component_available gaming && ! nvidia_present && WANTED[gaming]=1 - # On NVIDIA the conversion and "Gaming on NVIDIA" exclude each other: the one that is not on yet wins. - if nvidia_present && [[ "${WANTED[gaming]:-0}" == 1 && "${WANTED[nvidia]:-0}" == 1 ]]; then - if [[ "${CURRENT[gaming]:-0}" == 1 ]]; then WANTED[gaming]=0; WANTED[boot]=0; WANTED[silent]=0; WANTED[glyphs]=0 - else WANTED[nvidia]=0; WANTED[bigpicture]=0; WANTED[nvsilent]=0; fi - fi + [[ "${WANTED[single]:-0}" == 1 ]] && component_available gaming && WANTED[gaming]=1 if component_available gaming; then - [[ "${WANTED[gaming]:-0}" == 0 ]] && { nvidia_present || WANTED[single]=0; WANTED[boot]=0; } + [[ "${WANTED[gaming]:-0}" == 0 ]] && { WANTED[single]=0; WANTED[boot]=0; } else WANTED[boot]=0 fi diff --git a/lib/gamescope-nvidia.sh b/lib/gamescope-nvidia.sh index d0ceaab..c580a77 100644 --- a/lib/gamescope-nvidia.sh +++ b/lib/gamescope-nvidia.sh @@ -4,8 +4,9 @@ # https://github.com/theupriser/steamify-gamescope-nvidia; the package `steamify-gamescope-nvidia` is built here, on the PC, # and replaces `gamescope` (it provides it). The patch is opt-in: gamescope reads `gamescope_drm_gbm_scanout=1` from its # environment, which is set for the gaming session (gamescope-session's environment file, and environment.d). -# Used by the SteamOS conversion (`gaming_enable`/`gaming_disable`) on a supported NVIDIA card (`nvidia_supported`): -# GTX 16 / RTX 20 series or newer (Turing and later, what NVIDIA's open kernel driver supports). +# Used by the SteamOS conversion (`gaming_enable`/`gaming_disable`) on every NVIDIA PC (`nvidia_present`); the kernel +# parameters and the rest of lib/nvidia.sh's setup only on a supported card (`nvidia_supported`): GTX 16 / RTX 20 series or +# newer (Turing and later, what NVIDIA's open kernel driver supports). Tested on an RTX 5080 only. # Sourced by steamify.sh; not meant to be run on its own. GSN_PKG=steamify-gamescope-nvidia @@ -60,9 +61,12 @@ gsn_env_disable() { gsn_enable() { # Only on a supported NVIDIA card; elsewhere the stock gamescope is right. - nvidia_supported || return 0 - # What NVIDIA's DRM stack wants (lib/nvidia.sh): modeset/fbdev on the kernel command line, the modules in the - # initramfs, video memory kept over suspend, the 32-bit libraries. Takes effect at the next boot, like the session. + nvidia_present || return 0 + # A PC that had "Gaming on NVIDIA" on: Steam must not also start on the desktop. + nvidia_swap_out + # What NVIDIA's DRM stack wants (lib/nvidia.sh; a supported card only, the functions check): modeset/fbdev on the + # kernel command line, the modules in the initramfs, video memory kept over suspend, the 32-bit libraries. Takes + # effect at the next boot, like the session. nvidia_kernel_enable || return 1 nvidia_extras_enable || return 1 gsn_install_package || return 1 @@ -74,7 +78,7 @@ gsn_disable() { # The setting goes, and what nvidia_*_enable added; the packages stay (patched gamescope, 32-bit libraries), like # the other packages of the conversion (steam, gamescope-session-cachyos). gsn_env_disable - nvidia_supported || return 0 + nvidia_present || return 0 nvidia_extras_disable nvidia_kernel_disable } diff --git a/lib/menu.sh b/lib/menu.sh index 2d9103e..f081141 100644 --- a/lib/menu.sh +++ b/lib/menu.sh @@ -57,12 +57,9 @@ declare -A CURRENT WANTED component_available() { case "$1" in - # gamescope's own session shows a corrupted picture on NVIDIA unless it is the patched one (lib/gamescope-nvidia.sh, - # installed with the conversion on a supported card); "Gaming on NVIDIA" is the alternative there. Older NVIDIA - # cards only get the alternative (the conversion is shown anyway when it's already on, so it can be turned off). - gaming|boot|silent|glyphs) ! nvidia_present || gaming_status || nvidia_supported ;; - nvidia) nvidia_available ;; - bigpicture|nvsilent) bigpicture_available ;; + # The SteamOS conversion is offered on NVIDIA PCs too: it installs the patched gamescope there (lib/gamescope-nvidia.sh) + # and turns off "Gaming on NVIDIA" (lib/nvidia.sh), which is not offered any more (nvidia_available). + nvidia|bigpicture|nvsilent) nvidia_available ;; machine|poweroff) machine_available ;; vram) vram_available ;; # Steamify in the Steam library is for gaming mode's controller: not needed for Big Picture on the desktop (NVIDIA PCs; @@ -297,9 +294,8 @@ toggle_component() { component_selectable "$c" || return 1 WANTED[$c]=$(( 1 - WANTED[$c] )) # Single user mode only makes sense on top of the SteamOS conversion. - # (On NVIDIA the conversion isn't offered: single user mode logs in by itself, see lib/single-user.sh.) - if [[ "$c" == single && "${WANTED[single]}" == 1 ]] && component_available gaming && ! nvidia_present; then WANTED[gaming]=1; fi - if [[ "$c" == gaming && "${WANTED[gaming]}" == 0 ]]; then nvidia_present || WANTED[single]=0; WANTED[boot]=0; fi + if [[ "$c" == single && "${WANTED[single]}" == 1 ]] && component_available gaming; then WANTED[gaming]=1; fi + if [[ "$c" == gaming && "${WANTED[gaming]}" == 0 ]]; then WANTED[single]=0; WANTED[boot]=0; fi # Where to boot to is part of the conversion, too. if [[ "$c" == boot && "${WANTED[boot]}" == 1 ]]; then WANTED[gaming]=1; fi # Big Picture is opt-out: ticked along with "Gaming on NVIDIA". @@ -311,15 +307,6 @@ toggle_component() { if [[ "$c" == gaming && "${WANTED[gaming]}" == 0 ]]; then WANTED[silent]=0; WANTED[glyphs]=0; fi if [[ "$c" == silent && "${WANTED[silent]}" == 1 ]]; then WANTED[gaming]=1; fi if [[ "$c" == glyphs && "${WANTED[glyphs]}" == 1 ]]; then WANTED[gaming]=1; fi - # On NVIDIA the SteamOS conversion and "Gaming on NVIDIA" exclude each other (both would start Steam at login); - # single user mode works with either. - if nvidia_present; then - if [[ "$c" == nvidia && "${WANTED[nvidia]}" == 1 ]]; then - WANTED[gaming]=0; WANTED[boot]=0; WANTED[silent]=0; WANTED[glyphs]=0 - elif [[ "$c" =~ ^(gaming|boot|silent|glyphs)$ && "${WANTED[$c]}" == 1 && "${WANTED[gaming]}" == 1 ]]; then - WANTED[nvidia]=0; WANTED[bigpicture]=0; WANTED[nvsilent]=0 - fi - fi # The power-off fix is opt-out: ticked along with Steam Machine support. if [[ "$c" == machine ]]; then WANTED[poweroff]=${WANTED[machine]}; fi if [[ "$c" == poweroff && "${WANTED[poweroff]}" == 1 ]]; then WANTED[machine]=1; fi diff --git a/lib/nvidia.sh b/lib/nvidia.sh index c92fb7e..449a9d6 100644 --- a/lib/nvidia.sh +++ b/lib/nvidia.sh @@ -37,11 +37,21 @@ nvidia_present() { return 1 } -# The SteamOS conversion with the patched gamescope (lib/gamescope-nvidia.sh) replaces this on a supported card, so -# this is for older NVIDIA cards, and for a PC where it is already on (so it can be turned off, or swapped for the -# conversion). It and the conversion exclude each other (both would start Steam at login): the menu unticks one when -# the other is ticked. -nvidia_available() { nvidia_present && { ! nvidia_supported || nvidia_status; }; } +# Not offered any more (2.11.2): the SteamOS conversion with the patched gamescope (lib/gamescope-nvidia.sh) covers NVIDIA PCs. +# A PC that has this on keeps it until the conversion is turned on, which calls nvidia_swap_out. +nvidia_available() { return 1; } + +nvidia_swap_out() { + # The conversion takes over: Steam no longer starts by itself on the desktop at login (both would start it). Steam, the + # packages and the NVIDIA settings stay: the conversion needs them too. The state stays for the conversion's own disable. + nvidia_status || return 0 + info "Gaming on NVIDIA is replaced by the SteamOS conversion: Steam no longer starts on the desktop at login." + user_systemctl disable --now "$NVIDIA_UNIT" >/dev/null 2>&1 + rm -f "$(nvidia_unit_file)" + user_systemctl daemon-reload + krevert bigpicture + return 0 +} bigpicture_available() { nvidia_available; } nvidia_status() { diff --git a/ui/qml/AppState.qml b/ui/qml/AppState.qml index b15c5ff..6148d9c 100644 --- a/ui/qml/AppState.qml +++ b/ui/qml/AppState.qml @@ -78,21 +78,14 @@ Item { w[id] = !w[id]; // The same rules as the terminal menu (toggle_component). var hasGaming = items.some(function (i) { return i.id === "gaming"; }); - var hasNvidia = items.some(function (i) { return i.id === "nvidia"; }); - // Single user mode works without the conversion on NVIDIA PCs. - if (id === "gaming" && !w.gaming) { if (!hasNvidia) w.single = false; w.silent = false; w.glyphs = false; } - if (id === "single" && w.single && hasGaming && !hasNvidia) w.gaming = true; + if (id === "gaming" && !w.gaming) { w.single = false; w.silent = false; w.glyphs = false; } + if (id === "single" && w.single && hasGaming) w.gaming = true; if (id === "nvidia") w.bigpicture = w.nvidia; if (id === "bigpicture" && w.bigpicture) { w.nvidia = true; w.nvsilent = false; } if (id === "nvsilent" && w.nvsilent) { w.nvidia = true; w.bigpicture = false; } if (id === "nvidia" && !w.nvidia) w.nvsilent = false; if (id === "silent" && w.silent) w.gaming = true; if (id === "glyphs" && w.glyphs) w.gaming = true; - // On NVIDIA the conversion and "Gaming on NVIDIA" exclude each other (both would start Steam at login). - if (hasGaming && hasNvidia) { - if (id === "nvidia" && w.nvidia) { w.gaming = false; w.silent = false; w.glyphs = false; } - else if ((id === "gaming" || id === "silent" || id === "glyphs") && w[id] && w.gaming) { w.nvidia = false; w.bigpicture = false; w.nvsilent = false; } - } if (id === "machine") w.poweroff = w.machine; if (id === "poweroff" && w.poweroff) w.machine = true; if (id === "machine" && !w.machine) w.kpin = false; From 1c302b836b57e141b7e41297934d6ddb42ef4053 Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 18:28:43 +0200 Subject: [PATCH 08/26] feat: a PC that had Gaming on NVIDIA on gets the SteamOS conversion ticked, as an update --- lib/menu.sh | 4 ++++ lib/nvidia.sh | 6 ++++++ ui/qml/AppState.qml | 3 ++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/menu.sh b/lib/menu.sh index f081141..7c3d48c 100644 --- a/lib/menu.sh +++ b/lib/menu.sh @@ -113,6 +113,8 @@ feature_outdated() { # On, but set up by an older version of that feature (compared as # versions: 2.10.0 is newer than 2.9.0). local have want + # "Gaming on NVIDIA" is on: the SteamOS conversion replaces it, as an update of what the PC has (lib/nvidia.sh). + [[ "$1" == gaming ]] && nvidia_migration_pending && return 0 [[ "${CURRENT[$1]:-0}" == 1 ]] || return 1 have="$(state_get features "$1" "$FEATURE_BASELINE")" [[ "$have" == off ]] && have="$FEATURE_BASELINE" @@ -182,6 +184,8 @@ detect_components() { component_available "$c" || continue { feature_outdated "$c" || feature_new "$c"; } && WANTED[$c]=1 done + # "Gaming on NVIDIA" was on: its replacement, the SteamOS conversion, comes with the defaults of a first run. + nvidia_migration_pending && WANTED[glyphs]=1 # The kernel pin is no longer needed (the power-off fix), and HDMI # refresh boost needed the pin: whatever is left of either is unticked, # so a normal run removes it. diff --git a/lib/nvidia.sh b/lib/nvidia.sh index 449a9d6..fac2c2b 100644 --- a/lib/nvidia.sh +++ b/lib/nvidia.sh @@ -41,6 +41,12 @@ nvidia_present() { # A PC that has this on keeps it until the conversion is turned on, which calls nvidia_swap_out. nvidia_available() { return 1; } +nvidia_migration_pending() { + # "Gaming on NVIDIA" is on (set up before 2.11.2) and the SteamOS conversion that replaces it isn't: the menu ticks the + # conversion and shows it as an update, so a normal run moves the PC over (nvidia_swap_out in gsn_enable). + nvidia_present && nvidia_status && ! gaming_status 2>/dev/null +} + nvidia_swap_out() { # The conversion takes over: Steam no longer starts by itself on the desktop at login (both would start it). Steam, the # packages and the NVIDIA settings stay: the conversion needs them too. The state stays for the conversion's own disable. diff --git a/ui/qml/AppState.qml b/ui/qml/AppState.qml index 6148d9c..8448ba3 100644 --- a/ui/qml/AppState.qml +++ b/ui/qml/AppState.qml @@ -101,7 +101,8 @@ Item { if (it.kind !== "toggle") continue; if (hidden(it)) { if (it.on) p.push({ id: it.id, action: "off" }); continue; } if (it.parent && !want[it.parent]) { if (it.on) p.push({ id: it.id, action: "off" }); continue; } - if (want[it.id] && !it.on) p.push({ id: it.id, action: "on", isNew: !!it["new"] }); + // (An item that is off but flagged "update" replaces what the PC has: the conversion for "Gaming on NVIDIA".) + if (want[it.id] && !it.on) p.push({ id: it.id, action: it.update ? "update" : "on", isNew: !!it["new"] }); else if (!want[it.id] && it.on) p.push({ id: it.id, action: "off" }); else if (want[it.id] && (reapply || it.update)) p.push({ id: it.id, action: reapply ? "again" : "update" }); } From fc204bf1928cfe296e329d8eb54b0932805a5fb6 Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 18:30:05 +0200 Subject: [PATCH 09/26] feat: moving from Gaming on NVIDIA keeps how Steam started: Big Picture boots into gaming mode, otherwise the desktop --- lib/menu.sh | 13 +++++++++++-- ui/qml/AppState.qml | 3 ++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/menu.sh b/lib/menu.sh index 7c3d48c..08ca8ff 100644 --- a/lib/menu.sh +++ b/lib/menu.sh @@ -184,8 +184,17 @@ detect_components() { component_available "$c" || continue { feature_outdated "$c" || feature_new "$c"; } && WANTED[$c]=1 done - # "Gaming on NVIDIA" was on: its replacement, the SteamOS conversion, comes with the defaults of a first run. - nvidia_migration_pending && WANTED[glyphs]=1 + # "Gaming on NVIDIA" was on: its replacement, the SteamOS conversion, comes with the defaults of a first run, and the + # PC starts the way it did: Steam in Big Picture at login becomes booting into gaming mode, any other Steam start + # (a normal window, or silent in the tray) becomes booting into the desktop, with the silent start kept. + if nvidia_migration_pending; then + WANTED[glyphs]=1 + if bigpicture_status; then WANTED[boot]=0 + else + WANTED[boot]=1 + nvsilent_status && WANTED[silent]=1 + fi + fi # The kernel pin is no longer needed (the power-off fix), and HDMI # refresh boost needed the pin: whatever is left of either is unticked, # so a normal run removes it. diff --git a/ui/qml/AppState.qml b/ui/qml/AppState.qml index 8448ba3..a57a51b 100644 --- a/ui/qml/AppState.qml +++ b/ui/qml/AppState.qml @@ -65,7 +65,8 @@ Item { var w = {}; for (var i = 0; i < items.length; i++) w[items[i].id] = items[i].kind === "action" ? false : items[i].wanted; want = w; - boot = nowOn("boot") ? "desktop" : "gamescope"; + // (What the PC has, or what the backend ticked: "Gaming on NVIDIA" moving to the conversion keeps how Steam started.) + boot = want.boot ? "desktop" : "gamescope"; if (sel > rows.length) sel = 0; } Connections { target: backend; function onStatusChanged() { if (app.screen === "menu" || app.screen === "done") app.syncFromStatus(); } } From 7d5cc00380783c254a1c1099a0d31f42f56804da Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 18:36:21 +0200 Subject: [PATCH 10/26] feat: Steamify carries the patched gamescope's recipe and patch, no download of a separate repository --- CHANGELOG.md | 2 +- TECHNICAL.md | 15 ++-- lib/gamescope-nvidia.sh | 24 +++--- patches/README.md | 3 +- patches/gamescope-nvidia.PKGBUILD | 124 ++++++++++++++++++++++++++++++ 5 files changed, 149 insertions(+), 19 deletions(-) create mode 100644 patches/gamescope-nvidia.PKGBUILD diff --git a/CHANGELOG.md b/CHANGELOG.md index d3f2209..5b89d17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ one per merged pull request. ## 2.11.2 - 2026-10-13 -- **feat: the SteamOS conversion is offered on NVIDIA PCs again (GTX 16 / RTX 20 series or newer: Turing and later, the cards NVIDIA's open kernel driver supports): it builds and installs a patched gamescope from [steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia) (GBM-allocated scan-out buffers, NVIDIA's corrupted gaming-mode picture, gamescope#2309; a few minutes to build) and sets `gamescope_drm_gbm_scanout=1` for the session (`lib/gamescope-nvidia.sh`). It replaces "Gaming on NVIDIA", which is not offered any more (the kernel parameters, early modules, suspend memory and the 32-bit libraries come with the conversion on a supported card; a PC that had "Gaming on NVIDIA" on has it turned off when the conversion is turned on). Tested on an RTX 5080 (driver 615.78.08): Steam's gaming UI is clean with it and shows artifacts without. The package is pinned to one gamescope release: updating it is not automatic yet** +- **feat: the SteamOS conversion is offered on NVIDIA PCs again (GTX 16 / RTX 20 series or newer: Turing and later, the cards NVIDIA's open kernel driver supports): it builds and installs a patched gamescope from the recipe and patch Steamify carries (`patches/`, prepared in [steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia); gamescope 3.16.31, so a Steamify release builds the version it was tested with) (GBM-allocated scan-out buffers, NVIDIA's corrupted gaming-mode picture, gamescope#2309; a few minutes to build) and sets `gamescope_drm_gbm_scanout=1` for the session (`lib/gamescope-nvidia.sh`). It replaces "Gaming on NVIDIA", which is not offered any more (the kernel parameters, early modules, suspend memory and the 32-bit libraries come with the conversion on a supported card; a PC that had "Gaming on NVIDIA" on has it turned off when the conversion is turned on). Tested on an RTX 5080 (driver 615.78.08): Steam's gaming UI is clean with it and shows artifacts without. The package is pinned to one gamescope release: updating it is not automatic yet** - **feat: "Gaming on NVIDIA" also keeps video memory over suspend (`NVreg_PreserveVideoMemoryAllocations=1` in `/etc/modprobe.d/90-steamify-nvidia.conf`, the initramfs is rebuilt), enables `nvidia-suspend`/`nvidia-resume`/`nvidia-hibernate`, and installs `lib32-nvidia-utils` and `lib32-libxkbcommon` (32-bit games, the 32-bit MangoHud preload) on a supported card; off removes only what Steamify added. Untested on hardware yet** diff --git a/TECHNICAL.md b/TECHNICAL.md index 3ebe88a..966df2f 100644 --- a/TECHNICAL.md +++ b/TECHNICAL.md @@ -240,10 +240,13 @@ the Plasma desktop session, smooth and clean. Since 2.11.2 there is a second way: gamescope with GBM-allocated scan-out buffers (`lib/gamescope-nvidia.sh`). On an RTX 5080 (driver 615.78.08, 3440x1440@175) Steam's gaming UI in gamescope's DRM session is clean with it and shows artifacts everywhere -without. The patch is nine commits of [farnoy/gamescope](https://github.com/farnoy/gamescope) (`nvidia-gbm-wayland`), kept in -[steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia) with its PKGBUILD; `gsn_install_package` clones -that repository, builds the package as the user (`makepkg -sf`) and installs it with `pacman -U --ask 4` (the package provides and -conflicts with `gamescope`). It is opt-in inside gamescope: `gamescope_drm_gbm_scanout=1` in +without. The patch is nine commits of [farnoy/gamescope](https://github.com/farnoy/gamescope) (`nvidia-gbm-wayland`), carried in +`patches/` (`gamescope-gbm-scanout.patch` and the recipe `gamescope-nvidia.PKGBUILD`, kept in sync with +[steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia), where new gamescope versions are +prepared). `gsn_install_package` writes both into a temporary folder, builds the package there as the user (`makepkg -sf`: it +downloads Valve's gamescope at the PKGBUILD's `pkgver`, the version the patch was tested with, and its submodules; no checksums) and +installs it with `pacman -U --ask 4` (the package provides and conflicts with `gamescope`). A Steamify release therefore always +builds the gamescope version it was tested with. It is opt-in inside gamescope: `gamescope_drm_gbm_scanout=1` in `~/.config/gamescope-session/environment` and `~/.config/environment.d/99-steamify-gamescope-nvidia.conf`. The SteamOS conversion (`gaming_enable`) does this on every NVIDIA PC (`nvidia_present`: PCI vendor 0x10de, display class, its driver providing `nvidia_drm`), together with what "Gaming on NVIDIA" set up (on a supported card, `nvidia_supported`: GTX 16 / RTX 20 series or @@ -251,8 +254,8 @@ newer, Turing and later): the kernel parameters, the early modules, suspend memo `nvidia_extras_enable`). So the SteamOS conversion is the one gaming option on NVIDIA now, and "Gaming on NVIDIA" (below) is not offered any more (`nvidia_available`); a PC that had it on keeps it until the conversion is turned on, which turns it off (`nvidia_swap_out`). Turning the conversion off removes the setting and those settings, and keeps the packages. The package is -pinned to the gamescope release the patch was made for (`UPSTREAM_VERSION` in that repository): pacman does not update it, and -Steamify does not rebuild it yet. Tested on an RTX 5080 only. +pinned to the gamescope release in the PKGBUILD: pacman does not update it, a newer one comes with a newer Steamify +(the bump is prepared in the repository above), and Steamify does not rebuild it by itself yet. Tested on an RTX 5080 only. Before 2.11.2, with an NVIDIA GPU the SteamOS conversion (`gaming`, and its options `boot`, `single`, `glyphs`) wasn't offered, unless it was already on. `nvidia` ("Gaming on NVIDIA", `lib/nvidia.sh`) took its place (both would start Steam at login): it installs `steam` when missing (recorded in state `nvidia`, removed again only then) and enables the user diff --git a/lib/gamescope-nvidia.sh b/lib/gamescope-nvidia.sh index c580a77..2495523 100644 --- a/lib/gamescope-nvidia.sh +++ b/lib/gamescope-nvidia.sh @@ -1,8 +1,8 @@ #!/bin/bash # gamescope's own gaming mode on NVIDIA: a patched gamescope that allocates its scan-out buffers with GBM, which cures -# the corrupted picture (https://github.com/ValveSoftware/gamescope/issues/2309). The patch and the build recipe live in -# https://github.com/theupriser/steamify-gamescope-nvidia; the package `steamify-gamescope-nvidia` is built here, on the PC, -# and replaces `gamescope` (it provides it). The patch is opt-in: gamescope reads `gamescope_drm_gbm_scanout=1` from its +# the corrupted picture (https://github.com/ValveSoftware/gamescope/issues/2309). The patch and the build recipe are in +# patches/ (kept in sync with https://github.com/theupriser/steamify-gamescope-nvidia, where new gamescope versions are +# prepared); the package `steamify-gamescope-nvidia` is built here, on the PC, and replaces `gamescope` (it provides it). The patch is opt-in: gamescope reads `gamescope_drm_gbm_scanout=1` from its # environment, which is set for the gaming session (gamescope-session's environment file, and environment.d). # Used by the SteamOS conversion (`gaming_enable`/`gaming_disable`) on every NVIDIA PC (`nvidia_present`); the kernel # parameters and the rest of lib/nvidia.sh's setup only on a supported card (`nvidia_supported`): GTX 16 / RTX 20 series or @@ -10,7 +10,6 @@ # Sourced by steamify.sh; not meant to be run on its own. GSN_PKG=steamify-gamescope-nvidia -GSN_REPO=${GSN_REPO:-https://github.com/theupriser/steamify-gamescope-nvidia.git} GSN_ENV_LINE='gamescope_drm_gbm_scanout=1' GSN_ENV_D="${GSN_ENV_D:-$HOME/.config/environment.d/99-steamify-gamescope-nvidia.conf}" GSN_SESSION_ENV="${GSN_SESSION_ENV:-$HOME/.config/gamescope-session/environment}" @@ -22,22 +21,25 @@ gsn_env_set() { [[ -f "$GSN_ENV_D" ]] && grep -qsx "$GSN_ENV_LINE" "$GSN_SESSION gsn_status() { gsn_package_installed && gsn_env_set; } gsn_install_package() { - # Builds the package from the repo (makepkg runs as the user, never as root) and installs it. The build needs a few - # minutes: gamescope compiles from source. --ask 4 lets pacman replace the stock gamescope it conflicts with. + # Builds the package from the recipe and patch Steamify carries (patches/, so a Steamify release builds exactly the + # gamescope version it was tested with) and installs it. makepkg runs as the user, never as root, and downloads + # gamescope's sources (Valve's repository at the PKGBUILD's pkgver, and its submodules). The build needs a few minutes: + # gamescope compiles from source. --ask 4 lets pacman replace the stock gamescope it conflicts with. gsn_package_installed && return 0 info "Building the patched gamescope for NVIDIA (a few minutes)..." sudo pacman -S --needed --noconfirm base-devel git || { err "Installing the build tools failed."; return 1; } local dir pkg dir="$(mktemp -d)" || return 1 - if ! git clone --depth 1 "$GSN_REPO" "$dir/src"; then - err "Couldn't download $GSN_REPO." + patch_file gamescope-nvidia.PKGBUILD > "$dir/PKGBUILD" && + patch_file gamescope-gbm-scanout.patch > "$dir/gamescope-gbm-scanout.patch" || { + err "Couldn't write the build files." rm -rf "$dir"; return 1 - fi - if ! (cd "$dir/src" && makepkg -sf --noconfirm --nocheck); then + } + if ! (cd "$dir" && makepkg -sf --noconfirm --nocheck); then err "Building the patched gamescope failed (see above). The stock gamescope stays." rm -rf "$dir"; return 1 fi - pkg="$(ls "$dir"/src/"$GSN_PKG"-*.pkg.tar.* 2>/dev/null | grep -v -- '-debug-' | head -1)" + pkg="$(ls "$dir"/"$GSN_PKG"-*.pkg.tar.* 2>/dev/null | grep -v -- '-debug-' | head -1)" if [[ -z "$pkg" ]] || ! sudo pacman -U --noconfirm --ask 4 "$pkg"; then err "Installing the patched gamescope failed. The stock gamescope stays." rm -rf "$dir"; return 1 diff --git a/patches/README.md b/patches/README.md index ef8d40a..64f769b 100644 --- a/patches/README.md +++ b/patches/README.md @@ -16,4 +16,5 @@ read and reviewed on their own. `lib/*.sh` reads them with `patch_file | `steamify-os-release.sh`, `steamify-os-release.hook` | `lib/login-manager.sh` (SteamOS conversion) | What Steam's System settings show besides the OS name (which stays CachyOS's): `VERSION_ID=steamos-X.Y`, `VERSION_CODENAME=steam-machine`, `VARIANT`/`VARIANT_ID` Steamify with its version, in `/etc/os-release`; the pacman hook runs it again after cachyos-hooks (`fill SCRIPT=... VERSION=... STEAMOS=...`) | | `steamify-nvidia-initramfs.sh`, `steamify-nvidia-initramfs.hook` | `lib/nvidia.sh` (SteamOS conversion, NVIDIA fix) | The pacman hook (before the initramfs is built, after DKMS) and its script: the NVIDIA modules go into the initramfs only while every installed kernel has them, decided again at every kernel or driver change (`fill SCRIPT=...`) | | `cros-ec-cec-single-port.patch` | `lib/cec.sh` (HDMI-CEC) | Makes Valve's Steam Machine CEC driver find amdgpu's HDMI port | -| `gamescope-gbm-scanout.patch` | `lib/nvidia.sh` (gamescope on NVIDIA) | gamescope 3.16.31 patch: scan-out buffers allocated with GBM (opt-in, `gamescope_drm_gbm_scanout=1`), which cures the corrupted picture on NVIDIA; from farnoy/gamescope, see the header of the file | +| `gamescope-gbm-scanout.patch` | `lib/gamescope-nvidia.sh` (gamescope on NVIDIA) | gamescope 3.16.31 patch: scan-out buffers allocated with GBM (opt-in, `gamescope_drm_gbm_scanout=1`), which cures the corrupted picture on NVIDIA; from farnoy/gamescope, see the header of the file | +| `gamescope-nvidia.PKGBUILD` | `lib/gamescope-nvidia.sh` (gamescope on NVIDIA) | The recipe for the patched gamescope package (`steamify-gamescope-nvidia`, provides and conflicts with `gamescope`): Valve's gamescope at `pkgver` plus `gamescope-gbm-scanout.patch`; written with the patch to a temporary folder and built with `makepkg` | diff --git a/patches/gamescope-nvidia.PKGBUILD b/patches/gamescope-nvidia.PKGBUILD new file mode 100644 index 0000000..6b6b7e5 --- /dev/null +++ b/patches/gamescope-nvidia.PKGBUILD @@ -0,0 +1,124 @@ +# Maintainer: theupriser +# Based on Arch Linux's gamescope PKGBUILD (Maxime Gauduin, Giancarlo Razzolini, Sven-Hendrik Haase and contributors). +# +# gamescope with GBM-allocated scan-out buffers for NVIDIA (opt-in: gamescope_drm_gbm_scanout=1). +# The patch is gamescope-gbm-scanout.patch (next to this file; see its header for where it comes from). pkgver is the gamescope +# release the patch was made for and tested with. Kept in sync with https://github.com/theupriser/steamify-gamescope-nvidia; +# Steamify (lib/gamescope-nvidia.sh) writes both files into a temporary folder and runs makepkg there. + +pkgname=steamify-gamescope-nvidia +_srcname=gamescope +pkgver=3.16.31 +pkgrel=1 +pkgdesc='SteamOS session compositing window manager, with GBM scan-out for NVIDIA (opt-in: gamescope_drm_gbm_scanout=1)' +arch=(x86_64) +url=https://github.com/theupriser/steamify-gamescope-nvidia +license=( + BSD-2-Clause + BSD-3-Clause + LicenseRef-Reshade +) +provides=("gamescope=$pkgver") +conflicts=(gamescope gamescope-nvidia-gbm) +replaces=(gamescope-nvidia-gbm) +depends=( + glibc + mesa + libstdc++ + libgcc + lcms2 + libavif + libcap.so + libdecor + libdrm + libei + libinput + libpipewire-0.3.so + libx11 + libxcb + libxcomposite + libxcursor + libxdamage + libxext + libxfixes + libxi + libxkbcommon.so + libxmu + libxrender + libxres + libxtst + libxxf86vm + luajit + pixman + sdl2 + seatd + systemd-libs + vulkan-icd-loader + wayland + xcb-util-errors + xcb-util-wm + xorg-server-xwayland +) +makedepends=( + benchmark + cmake + git + glslang + meson + ninja + vulkan-headers + wayland-protocols + catch2 +) +source=( + gamescope::git+https://github.com/ValveSoftware/gamescope.git#commit=${pkgver} + gamescope-gbm-scanout.patch + git+https://gitlab.freedesktop.org/emersion/libdisplay-info.git + git+https://gitlab.freedesktop.org/emersion/libliftoff.git + git+https://github.com/ValveSoftware/openvr.git + git+https://github.com/Joshua-Ashton/reshade.git + git+https://github.com/KhronosGroup/SPIRV-Headers.git + git+https://github.com/Joshua-Ashton/vkroots.git + git+https://gitlab.freedesktop.org/wlroots/wlroots.git +) +b2sums=('SKIP' + 'SKIP' + 'SKIP' + 'SKIP' + 'SKIP' + 'SKIP' + 'SKIP' + 'SKIP' + 'SKIP') + +prepare() { + cd gamescope + + # GBM scan-out for NVIDIA. If it no longer applies to this gamescope version, stop here: the build must not + # silently produce an unpatched gamescope under this package's name. + git apply --check ../gamescope-gbm-scanout.patch || { echo "gbm patch does not apply to gamescope ${pkgver}" >&2; return 1; } + git apply ../gamescope-gbm-scanout.patch + + meson subprojects download + + for submodule in src/reshade subprojects/{libdisplay-info,libliftoff,openvr,vkroots,wlroots} thirdparty/SPIRV-Headers; do + git submodule init ${submodule} + git config submodule.${submodule}.url ../${submodule##*/} + done + git -c protocol.file.allow=always submodule update +} + +build() { + arch-meson gamescope build \ + -Dforce_fallback_for=glm,stb,libdisplay-info,libliftoff,vkroots \ + -Dpipewire=enabled + meson compile -C build +} + +package() { + DESTDIR="${pkgdir}" meson install -C build \ + --skip-subprojects + install -Dm 644 gamescope/LICENSE -t "${pkgdir}"/usr/share/licenses/${pkgname}/ +} + +# vim: ts=2 sw=2 et: From bc49009fcc914c8402fe268aa54136a5fd061177 Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 18:37:21 +0200 Subject: [PATCH 11/26] fix: build the patched gamescope in the user's cache folder, not /tmp (a tmpfs in the installer's chroot) --- lib/gamescope-nvidia.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/gamescope-nvidia.sh b/lib/gamescope-nvidia.sh index 2495523..dca71af 100644 --- a/lib/gamescope-nvidia.sh +++ b/lib/gamescope-nvidia.sh @@ -28,8 +28,9 @@ gsn_install_package() { gsn_package_installed && return 0 info "Building the patched gamescope for NVIDIA (a few minutes)..." sudo pacman -S --needed --noconfirm base-devel git || { err "Installing the build tools failed."; return 1; } - local dir pkg - dir="$(mktemp -d)" || return 1 + local dir pkg cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify" + # On disk, not /tmp: the installer's chroot has a tmpfs there (RAM), and the build is 1-2 GB. + mkdir -p "$cache" && dir="$(mktemp -d -p "$cache" gamescope-build.XXXXXX)" || return 1 patch_file gamescope-nvidia.PKGBUILD > "$dir/PKGBUILD" && patch_file gamescope-gbm-scanout.patch > "$dir/gamescope-gbm-scanout.patch" || { err "Couldn't write the build files." From ccd30b7711b008421470ed765edda4f9118033e7 Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 18:44:15 +0200 Subject: [PATCH 12/26] fix: the Steam Machine's CEC driver comes from a carried, checksum-pinned copy when the GitHub download fails --- CHANGELOG.md | 2 + lib/cec.sh | 13 +- patches/README.md | 1 + patches/cros-ec-cec.c | 621 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 633 insertions(+), 4 deletions(-) create mode 100644 patches/cros-ec-cec.c diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b89d17..89c443e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ one per merged pull request. ## 2.11.2 - 2026-10-13 +- **fix: HDMI-CEC on the Steam Machine no longer needs GitHub: when downloading Valve's CEC driver fails, Steamify uses the copy it carries (`patches/cros-ec-cec.c`), checked against the same pinned sha256** + - **feat: the SteamOS conversion is offered on NVIDIA PCs again (GTX 16 / RTX 20 series or newer: Turing and later, the cards NVIDIA's open kernel driver supports): it builds and installs a patched gamescope from the recipe and patch Steamify carries (`patches/`, prepared in [steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia); gamescope 3.16.31, so a Steamify release builds the version it was tested with) (GBM-allocated scan-out buffers, NVIDIA's corrupted gaming-mode picture, gamescope#2309; a few minutes to build) and sets `gamescope_drm_gbm_scanout=1` for the session (`lib/gamescope-nvidia.sh`). It replaces "Gaming on NVIDIA", which is not offered any more (the kernel parameters, early modules, suspend memory and the 32-bit libraries come with the conversion on a supported card; a PC that had "Gaming on NVIDIA" on has it turned off when the conversion is turned on). Tested on an RTX 5080 (driver 615.78.08): Steam's gaming UI is clean with it and shows artifacts without. The package is pinned to one gamescope release: updating it is not automatic yet** - **feat: "Gaming on NVIDIA" also keeps video memory over suspend (`NVreg_PreserveVideoMemoryAllocations=1` in `/etc/modprobe.d/90-steamify-nvidia.conf`, the initramfs is rebuilt), enables `nvidia-suspend`/`nvidia-resume`/`nvidia-hibernate`, and installs `lib32-nvidia-utils` and `lib32-libxkbcommon` (32-bit games, the 32-bit MangoHud preload) on a supported card; off removes only what Steamify added. Untested on hardware yet** diff --git a/lib/cec.sh b/lib/cec.sh index 0171646..f221993 100644 --- a/lib/cec.sh +++ b/lib/cec.sh @@ -73,11 +73,16 @@ cec_driver_enable() { cp "$CEC_DRIVER_CACHE" "$tmp/cros-ec-cec.c" else info "Downloading Valve's Steam Machine CEC driver..." - if ! curl -fsL --retry 2 "$CEC_DRIVER_URL" -o "$tmp/cros-ec-cec.c" || + if ! curl -fsL --retry 2 --max-time 60 "$CEC_DRIVER_URL" -o "$tmp/cros-ec-cec.c" || ! echo "$CEC_DRIVER_SHA256 $tmp/cros-ec-cec.c" | sha256sum -c --quiet -; then - rm -rf "$tmp" - err "Downloading Valve's CEC driver failed (or its checksum didn't match)." - return 1 + # GitHub is down, rate-limits us, or sent something else: Steamify carries the same file (checked the same way). + warn "Downloading Valve's CEC driver failed (or its checksum didn't match): using the copy Steamify carries." + patch_file cros-ec-cec.c > "$tmp/cros-ec-cec.c" + if ! echo "$CEC_DRIVER_SHA256 $tmp/cros-ec-cec.c" | sha256sum -c --quiet -; then + rm -rf "$tmp" + err "Steamify's own copy of Valve's CEC driver doesn't match the pinned checksum (a new pin needs a new copy in patches/)." + return 1 + fi fi # The name carries the checksum: a newer pin gets its own file, the old one goes. sudo find "${CEC_DRIVER_CACHE%/*}" -maxdepth 1 -name 'cros-ec-cec-*.c' ! -name "${CEC_DRIVER_CACHE##*/}" -delete 2>/dev/null diff --git a/patches/README.md b/patches/README.md index 64f769b..cfbfd6c 100644 --- a/patches/README.md +++ b/patches/README.md @@ -18,3 +18,4 @@ read and reviewed on their own. `lib/*.sh` reads them with `patch_file | `cros-ec-cec-single-port.patch` | `lib/cec.sh` (HDMI-CEC) | Makes Valve's Steam Machine CEC driver find amdgpu's HDMI port | | `gamescope-gbm-scanout.patch` | `lib/gamescope-nvidia.sh` (gamescope on NVIDIA) | gamescope 3.16.31 patch: scan-out buffers allocated with GBM (opt-in, `gamescope_drm_gbm_scanout=1`), which cures the corrupted picture on NVIDIA; from farnoy/gamescope, see the header of the file | | `gamescope-nvidia.PKGBUILD` | `lib/gamescope-nvidia.sh` (gamescope on NVIDIA) | The recipe for the patched gamescope package (`steamify-gamescope-nvidia`, provides and conflicts with `gamescope`): Valve's gamescope at `pkgver` plus `gamescope-gbm-scanout.patch`; written with the patch to a temporary folder and built with `makepkg` | +| `cros-ec-cec.c` | `lib/cec.sh` (HDMI-CEC) | Valve's Steam Machine CEC driver (GPL-2.0+, from evlaV/linux-integration at the pinned commit): the backup when downloading it from GitHub fails; used only if its sha256 equals `CEC_DRIVER_SHA256` (a new pin needs a new copy) | diff --git a/patches/cros-ec-cec.c b/patches/cros-ec-cec.c new file mode 100644 index 0000000..a149619 --- /dev/null +++ b/patches/cros-ec-cec.c @@ -0,0 +1,621 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * CEC driver for ChromeOS Embedded Controller + * + * Copyright (c) 2018 BayLibre, SAS + * Author: Neil Armstrong + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "cros-ec-cec" + +/** + * struct cros_ec_cec_port - Driver data for a single EC CEC port + * + * @port_num: port number + * @adap: CEC adapter + * @notify: CEC notifier pointer + * @rx_msg: storage for a received message + * @cros_ec_cec: pointer to the parent struct + */ +struct cros_ec_cec_port { + int port_num; + struct cec_adapter *adap; + struct cec_notifier *notify; + struct cec_msg rx_msg; + struct cros_ec_cec *cros_ec_cec; +}; + +/** + * struct cros_ec_cec - Driver data for EC CEC + * + * @cros_ec: Pointer to EC device + * @notifier: Notifier info for responding to EC events + * @write_cmd_version: Highest supported version of EC_CMD_CEC_WRITE_MSG. + * @num_ports: Number of CEC ports + * @ports: Array of ports + */ +struct cros_ec_cec { + struct cros_ec_device *cros_ec; + struct notifier_block notifier; + int write_cmd_version; + int num_ports; + struct cros_ec_cec_port *ports[EC_CEC_MAX_PORTS]; +}; + +static void cros_ec_cec_received_message(struct cros_ec_cec_port *port, + uint8_t *msg, uint8_t len) +{ + if (len > CEC_MAX_MSG_SIZE) + len = CEC_MAX_MSG_SIZE; + + port->rx_msg.len = len; + memcpy(port->rx_msg.msg, msg, len); + + cec_received_msg(port->adap, &port->rx_msg); +} + +static void handle_cec_message(struct cros_ec_cec *cros_ec_cec) +{ + struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; + uint8_t *cec_message = cros_ec->event_data.data.cec_message; + unsigned int len = cros_ec->event_size; + struct cros_ec_cec_port *port; + /* + * There are two ways of receiving CEC messages: + * 1. Old EC firmware which only supports one port sends the data in a + * cec_message MKBP event. + * 2. New EC firmware which supports multiple ports uses + * EC_MKBP_CEC_HAVE_DATA to notify that data is ready and + * EC_CMD_CEC_READ_MSG to read it. + * Check that the EC only has one CEC port, and then we can assume the + * message is from port 0. + */ + if (cros_ec_cec->num_ports != 1) { + dev_err(cros_ec->dev, + "received cec_message on device with %d ports\n", + cros_ec_cec->num_ports); + return; + } + port = cros_ec_cec->ports[0]; + + cros_ec_cec_received_message(port, cec_message, len); +} + +static void cros_ec_cec_read_message(struct cros_ec_cec_port *port) +{ + struct cros_ec_device *cros_ec = port->cros_ec_cec->cros_ec; + struct ec_params_cec_read params = { + .port = port->port_num, + }; + struct ec_response_cec_read response; + int ret = 0; + int count = 0; + + /* NOTE read as many messages as we can, return value from cros_ec_cmd + * here should either equal to the bytes transferred or a negative + * error code, so as long as we get positive integers we are + * reading messages! + */ + do { + ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_READ_MSG, ¶ms, + sizeof(params), &response, sizeof(response)); + if (ret > 0) { + ++count; + cros_ec_cec_received_message(port, response.msg, response.msg_len); + } + } + while (ret > 0); + + if (ret < 0 && count == 0) { + dev_err(cros_ec->dev, + "error reading CEC message on EC: %d\n", ret); + } +} + +static void handle_cec_event(struct cros_ec_cec *cros_ec_cec) +{ + struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; + uint32_t cec_events = cros_ec->event_data.data.cec_events; + uint32_t port_num = EC_MKBP_EVENT_CEC_GET_PORT(cec_events); + uint32_t events = EC_MKBP_EVENT_CEC_GET_EVENTS(cec_events); + struct cros_ec_cec_port *port; + + if (port_num >= cros_ec_cec->num_ports) { + dev_err(cros_ec->dev, + "received CEC event for invalid port %d\n", port_num); + return; + } + port = cros_ec_cec->ports[port_num]; + + if (events & EC_MKBP_CEC_SEND_OK) + cec_transmit_attempt_done(port->adap, CEC_TX_STATUS_OK); + + /* FW takes care of all retries, tell core to avoid more retries */ + if (events & EC_MKBP_CEC_SEND_FAILED) + cec_transmit_attempt_done(port->adap, + CEC_TX_STATUS_MAX_RETRIES | + CEC_TX_STATUS_NACK); + + if (events & EC_MKBP_CEC_HAVE_DATA) + cros_ec_cec_read_message(port); +} + +static int cros_ec_cec_event(struct notifier_block *nb, + unsigned long queued_during_suspend, + void *_notify) +{ + struct cros_ec_cec *cros_ec_cec; + struct cros_ec_device *cros_ec; + + cros_ec_cec = container_of(nb, struct cros_ec_cec, notifier); + cros_ec = cros_ec_cec->cros_ec; + + if (cros_ec->event_data.event_type == EC_MKBP_EVENT_CEC_EVENT) { + handle_cec_event(cros_ec_cec); + return NOTIFY_OK; + } + + if (cros_ec->event_data.event_type == EC_MKBP_EVENT_CEC_MESSAGE) { + handle_cec_message(cros_ec_cec); + return NOTIFY_OK; + } + + return NOTIFY_DONE; +} + +static int cros_ec_cec_set_log_addr(struct cec_adapter *adap, u8 logical_addr) +{ + struct cros_ec_cec_port *port = adap->priv; + struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec; + struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; + struct ec_params_cec_set params = { + .cmd = CEC_CMD_LOGICAL_ADDRESS, + .port = port->port_num, + .val = logical_addr, + }; + int ret; + + ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_SET, ¶ms, sizeof(params), + NULL, 0); + if (ret < 0) { + dev_err(cros_ec->dev, + "error setting CEC logical address on EC: %d\n", ret); + return ret; + } + + return 0; +} + +static int cros_ec_cec_transmit(struct cec_adapter *adap, u8 attempts, + u32 signal_free_time, struct cec_msg *cec_msg) +{ + struct cros_ec_cec_port *port = adap->priv; + struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec; + struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; + struct ec_params_cec_write params; + struct ec_params_cec_write_v1 params_v1; + int ret; + + if (cros_ec_cec->write_cmd_version == 0) { + memcpy(params.msg, cec_msg->msg, cec_msg->len); + ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_WRITE_MSG, ¶ms, + cec_msg->len, NULL, 0); + } else { + params_v1.port = port->port_num; + params_v1.msg_len = cec_msg->len; + memcpy(params_v1.msg, cec_msg->msg, cec_msg->len); + ret = cros_ec_cmd(cros_ec, cros_ec_cec->write_cmd_version, + EC_CMD_CEC_WRITE_MSG, ¶ms_v1, + sizeof(params_v1), NULL, 0); + } + + if (ret < 0) { + dev_err(cros_ec->dev, + "error writing CEC msg on EC: %d\n", ret); + return ret; + } + + return 0; +} + +static int cros_ec_cec_adap_enable(struct cec_adapter *adap, bool enable) +{ + struct cros_ec_cec_port *port = adap->priv; + struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec; + struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; + struct ec_params_cec_set params = { + .cmd = CEC_CMD_ENABLE, + .port = port->port_num, + .val = enable, + }; + int ret; + + ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_SET, ¶ms, sizeof(params), + NULL, 0); + if (ret < 0) { + dev_err(cros_ec->dev, + "error %sabling CEC on EC: %d\n", + (enable ? "en" : "dis"), ret); + return ret; + } + + return 0; +} + +static const struct cec_adap_ops cros_ec_cec_ops = { + .adap_enable = cros_ec_cec_adap_enable, + .adap_log_addr = cros_ec_cec_set_log_addr, + .adap_transmit = cros_ec_cec_transmit, +}; + +#ifdef CONFIG_PM_SLEEP +static int cros_ec_cec_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct cros_ec_cec *cros_ec_cec = dev_get_drvdata(&pdev->dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(cros_ec_cec->cros_ec->irq); + + return 0; +} + +static int cros_ec_cec_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct cros_ec_cec *cros_ec_cec = dev_get_drvdata(&pdev->dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(cros_ec_cec->cros_ec->irq); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(cros_ec_cec_pm_ops, + cros_ec_cec_suspend, cros_ec_cec_resume); + +#if IS_ENABLED(CONFIG_PCI) && IS_ENABLED(CONFIG_DMI) + +/* + * Specify the DRM device name handling the HDMI output and the HDMI connector + * corresponding to each CEC port. The order of connectors must match the order + * in the EC (first connector is EC port 0, ...), and the number of connectors + * must match the number of ports in the EC (which can be queried using the + * EC_CMD_CEC_PORT_COUNT host command). + */ + +struct cec_dmi_match { + const char *sys_vendor; + const char *product_name; + const char *devname; + const char *const *conns; +}; + +static const char *const port_b_conns[] = { "Port B", NULL }; +static const char *const port_c_conns[] = { "Port C", NULL }; +static const char *const port_db_conns[] = { "Port D", "Port B", NULL }; +static const char *const port_ba_conns[] = { "Port B", "Port A", NULL }; +static const char *const port_ab_conns[] = { "Port A", "Port B", NULL }; +static const char *const port_d_conns[] = { "Port D", NULL }; + +static const struct cec_dmi_match cec_dmi_match_table[] = { + /* AMD Lilac */ + { "AMD", "Lilac", "0000:03:00.0", port_c_conns }, + /* Valve Fremont */ + { "OEM", "F7F", "0000:03:00.0", port_c_conns }, + { "Valve", "Fremont", "0000:03:00.0", port_c_conns }, + /* Google Fizz */ + { "Google", "Fizz", "0000:00:02.0", port_b_conns }, + /* Google Brask */ + { "Google", "Brask", "0000:00:02.0", port_b_conns }, + /* Google Moli */ + { "Google", "Moli", "0000:00:02.0", port_b_conns }, + /* Google Kinox */ + { "Google", "Kinox", "0000:00:02.0", port_b_conns }, + /* Google Kuldax */ + { "Google", "Kuldax", "0000:00:02.0", port_b_conns }, + /* Google Aurash */ + { "Google", "Aurash", "0000:00:02.0", port_b_conns }, + /* Google Gladios */ + { "Google", "Gladios", "0000:00:02.0", port_b_conns }, + /* Google Lisbon */ + { "Google", "Lisbon", "0000:00:02.0", port_b_conns }, + /* Google Dibbi */ + { "Google", "Dibbi", "0000:00:02.0", port_db_conns }, + /* Google Constitution */ + { "Google", "Constitution", "0000:00:02.0", port_ba_conns }, + /* Google Boxy */ + { "Google", "Boxy", "0000:00:02.0", port_d_conns }, + /* Google Taranza */ + { "Google", "Taranza", "0000:00:02.0", port_db_conns }, + /* Google Dexi */ + { "Google", "Dexi", "0000:00:02.0", port_db_conns }, + /* Google Dita */ + { "Google", "Dita", "0000:00:02.0", port_db_conns }, + /* Google Dirks */ + { "Google", "Dirks", "0000:00:02.0", port_ab_conns }, + /* Google Moxie */ + { "Google", "Moxie", "0000:00:02.0", port_b_conns }, + /* AMD Lilac */ + { "AMD", "Lilac", "0000:06:00.0", port_c_conns }, +}; + +static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, + const char * const **conns) +{ + int i; + + for (i = 0 ; i < ARRAY_SIZE(cec_dmi_match_table) ; ++i) { + const struct cec_dmi_match *m = &cec_dmi_match_table[i]; + + if (dmi_match(DMI_SYS_VENDOR, m->sys_vendor) && + dmi_match(DMI_PRODUCT_NAME, m->product_name)) { + struct device *d; + + /* Find the device, bail out if not yet registered */ + d = bus_find_device_by_name(&pci_bus_type, NULL, + m->devname); + if (!d) + return ERR_PTR(-EPROBE_DEFER); + put_device(d); + *conns = m->conns; + return d; + } + } + + /* Hardware support must be added in the cec_dmi_match_table */ + dev_warn(dev, "CEC notifier not configured for this hardware\n"); + + return ERR_PTR(-ENODEV); +} + +#else + +static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, + const char * const **conns) +{ + return ERR_PTR(-ENODEV); +} + +#endif + +static int cros_ec_cec_get_num_ports(struct cros_ec_cec *cros_ec_cec) +{ + struct ec_response_cec_port_count response; + int ret; + + ret = cros_ec_cmd(cros_ec_cec->cros_ec, 0, EC_CMD_CEC_PORT_COUNT, NULL, + 0, &response, sizeof(response)); + if (ret < 0) { + /* + * Old EC firmware only supports one port and does not support + * the port count command, so fall back to assuming one port. + */ + cros_ec_cec->num_ports = 1; + return 0; + } + + if (response.port_count == 0) { + dev_err(cros_ec_cec->cros_ec->dev, + "EC reports 0 CEC ports\n"); + return -ENODEV; + } + + if (response.port_count > EC_CEC_MAX_PORTS) { + dev_err(cros_ec_cec->cros_ec->dev, + "EC reports too many ports: %d\n", response.port_count); + return -EINVAL; + } + + cros_ec_cec->num_ports = response.port_count; + return 0; +} + +static int cros_ec_cec_get_write_cmd_version(struct cros_ec_cec *cros_ec_cec) +{ + struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; + struct ec_params_get_cmd_versions_v1 params = { + .cmd = EC_CMD_CEC_WRITE_MSG, + }; + struct ec_response_get_cmd_versions response; + int ret; + + ret = cros_ec_cmd(cros_ec, 1, EC_CMD_GET_CMD_VERSIONS, ¶ms, + sizeof(params), &response, sizeof(response)); + if (ret < 0) { + dev_err(cros_ec->dev, + "error getting CEC write command version: %d\n", ret); + return ret; + } + + if (response.version_mask & EC_VER_MASK(1)) { + cros_ec_cec->write_cmd_version = 1; + } else { + if (cros_ec_cec->num_ports != 1) { + dev_err(cros_ec->dev, + "v0 write command only supports 1 port, %d reported\n", + cros_ec_cec->num_ports); + return -EINVAL; + } + cros_ec_cec->write_cmd_version = 0; + } + + return 0; +} + +static int cros_ec_cec_init_port(struct device *dev, + struct cros_ec_cec *cros_ec_cec, + int port_num, struct device *hdmi_dev, + const char * const *conns) +{ + struct cros_ec_cec_port *port; + int ret; + + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + + port->cros_ec_cec = cros_ec_cec; + port->port_num = port_num; + + port->adap = cec_allocate_adapter(&cros_ec_cec_ops, port, DRV_NAME, + CEC_CAP_DEFAULTS | + CEC_CAP_CONNECTOR_INFO, 1); + if (IS_ERR(port->adap)) + return PTR_ERR(port->adap); + + if (!conns[port_num]) { + dev_err(dev, "no conn for port %d\n", port_num); + ret = -ENODEV; + goto out_probe_adapter; + } + + port->notify = cec_notifier_cec_adap_register(hdmi_dev, conns[port_num], + port->adap); + if (!port->notify) { + ret = -ENOMEM; + goto out_probe_adapter; + } + + ret = cec_register_adapter(port->adap, dev); + if (ret < 0) + goto out_probe_notify; + + cros_ec_cec->ports[port_num] = port; + + return 0; + +out_probe_notify: + cec_notifier_cec_adap_unregister(port->notify, port->adap); +out_probe_adapter: + cec_delete_adapter(port->adap); + return ret; +} + +static int cros_ec_cec_probe(struct platform_device *pdev) +{ + struct cros_ec_dev *ec_dev = dev_get_drvdata(pdev->dev.parent); + struct cros_ec_device *cros_ec = ec_dev->ec_dev; + struct cros_ec_cec *cros_ec_cec; + struct cros_ec_cec_port *port; + struct device *hdmi_dev; + const char * const *conns = NULL; + int ret; + + hdmi_dev = cros_ec_cec_find_hdmi_dev(&pdev->dev, &conns); + if (IS_ERR(hdmi_dev)) + return PTR_ERR(hdmi_dev); + + cros_ec_cec = devm_kzalloc(&pdev->dev, sizeof(*cros_ec_cec), + GFP_KERNEL); + if (!cros_ec_cec) + return -ENOMEM; + + platform_set_drvdata(pdev, cros_ec_cec); + cros_ec_cec->cros_ec = cros_ec; + + device_init_wakeup(&pdev->dev, 1); + + ret = cros_ec_cec_get_num_ports(cros_ec_cec); + if (ret) + return ret; + + ret = cros_ec_cec_get_write_cmd_version(cros_ec_cec); + if (ret) + return ret; + + for (int i = 0; i < cros_ec_cec->num_ports; i++) { + ret = cros_ec_cec_init_port(&pdev->dev, cros_ec_cec, i, + hdmi_dev, conns); + if (ret) + goto unregister_ports; + } + + /* Get CEC events from the EC. */ + cros_ec_cec->notifier.notifier_call = cros_ec_cec_event; + ret = blocking_notifier_chain_register(&cros_ec->event_notifier, + &cros_ec_cec->notifier); + if (ret) { + dev_err(&pdev->dev, "failed to register notifier\n"); + goto unregister_ports; + } + + return 0; + +unregister_ports: + /* + * Unregister any adapters which have been registered. We don't add the + * port to the array until the adapter has been registered successfully, + * so any non-NULL ports must have been registered. + */ + for (int i = 0; i < cros_ec_cec->num_ports; i++) { + port = cros_ec_cec->ports[i]; + if (!port) + break; + cec_notifier_cec_adap_unregister(port->notify, port->adap); + cec_unregister_adapter(port->adap); + } + return ret; +} + +static void cros_ec_cec_remove(struct platform_device *pdev) +{ + struct cros_ec_cec *cros_ec_cec = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + struct cros_ec_cec_port *port; + int ret; + + /* + * blocking_notifier_chain_unregister() only fails if the notifier isn't + * in the list. We know it was added to it by .probe(), so there should + * be no need for error checking. Be cautious and still check. + */ + ret = blocking_notifier_chain_unregister( + &cros_ec_cec->cros_ec->event_notifier, + &cros_ec_cec->notifier); + if (ret) + dev_err(dev, "failed to unregister notifier\n"); + + for (int i = 0; i < cros_ec_cec->num_ports; i++) { + port = cros_ec_cec->ports[i]; + cec_notifier_cec_adap_unregister(port->notify, port->adap); + cec_unregister_adapter(port->adap); + } +} + +static const struct platform_device_id cros_ec_cec_id[] = { + { DRV_NAME, 0 }, + {} +}; +MODULE_DEVICE_TABLE(platform, cros_ec_cec_id); + +static struct platform_driver cros_ec_cec_driver = { + .probe = cros_ec_cec_probe, + .remove = cros_ec_cec_remove, + .driver = { + .name = DRV_NAME, + .pm = &cros_ec_cec_pm_ops, + }, + .id_table = cros_ec_cec_id, +}; + +module_platform_driver(cros_ec_cec_driver); + +MODULE_DESCRIPTION("CEC driver for ChromeOS ECs"); +MODULE_AUTHOR("Neil Armstrong "); +MODULE_LICENSE("GPL"); From d99e9a93ac6c11fc73f35eef33619251707eb29f Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 18:44:43 +0200 Subject: [PATCH 13/26] docs: credit Valve's kernel for the power-off fix and CEC driver, list the code of other projects with its licenses --- README.md | 10 ++++++++++ patches/steamify-fremont-poweroff.c | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/README.md b/README.md index ad57ed9..01498b3 100644 --- a/README.md +++ b/README.md @@ -187,6 +187,16 @@ Contributing (or an AI agent)? Read [AGENTS.md](AGENTS.md). MIT - do whatever you want with it. See [LICENSE.md](LICENSE.md). +### Code from other projects + +Some files in `patches/` are not MIT. They keep their own license, and each file says where it comes from: + +| File | What | License and source | +|---|---|---| +| `steamify-fremont-poweroff.c` | Kernel module for the Steam Machine's power-off fix. It does what Valve's Steam Machine kernel does for this (clears the S4 wake bit of GPIO pin 18 at probe), but at power-off, for kernels without Valve's change. Valve's kernel: [evlaV/linux-integration](https://github.com/evlaV/linux-integration). | GPL-2.0, like the Linux kernel it is built into | +| `cros-ec-cec.c` | Valve's Steam Machine HDMI-CEC driver (ChromeOS EC CEC, Copyright BayLibre; Valve's version of it), at a pinned commit of [evlaV/linux-integration](https://github.com/evlaV/linux-integration). Used when it can't be downloaded. | GPL-2.0+, unmodified (Steamify's `cros-ec-cec-single-port.patch` is applied when it is built) | +| `gamescope-gbm-scanout.patch` | GBM scan-out for gamescope on NVIDIA: nine commits of [farnoy/gamescope](https://github.com/farnoy/gamescope) on [ValveSoftware/gamescope](https://github.com/ValveSoftware/gamescope). | gamescope's license (BSD-2-Clause) | + ## Disclaimer Steamify CachyOS is an unofficial community project. It is not affiliated diff --git a/patches/steamify-fremont-poweroff.c b/patches/steamify-fremont-poweroff.c index b7c7c8a..0a3f1bb 100644 --- a/patches/steamify-fremont-poweroff.c +++ b/patches/steamify-fremont-poweroff.c @@ -7,6 +7,11 @@ * leaves set on GPIO pin 18 (_SB.PCI0.GPP6) stays set, and the machine starts again right after powering off. * Valve's kernel clears that bit at probe on Fremont (not for upstream); * this does the same right before power-off, for kernels without it. + * + * What it does follows Valve's Steam Machine kernel + * (https://github.com/evlaV/linux-integration, GPL-2.0 like the rest of the + * Linux kernel); this module is Steamify's own implementation of it, also + * GPL-2.0. Not affiliated with or endorsed by Valve Corporation. */ #include #include From 40ed1259f6f3c83237fea5355d703207ccb9b45c Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 18:47:29 +0200 Subject: [PATCH 14/26] feat: the patched gamescope comes from the pinned GitHub release (sha256), else the copy on the ISO, else a local build --- .no-release-yet | 2 + CHANGELOG.md | 6 +-- lib/gamescope-nvidia.sh | 91 +++++++++++++++++++++++++++++++++-------- 3 files changed, 78 insertions(+), 21 deletions(-) create mode 100644 .no-release-yet diff --git a/.no-release-yet b/.no-release-yet new file mode 100644 index 0000000..eedb58b --- /dev/null +++ b/.no-release-yet @@ -0,0 +1,2 @@ +Not tested on hardware yet: the whole Steamify flow for the patched gamescope on NVIDIA (apply, reboot, session). +Delete this file when it was, after asking the user (AGENTS.md). diff --git a/CHANGELOG.md b/CHANGELOG.md index 89c443e..d1e372a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,11 @@ one per merged pull request. ## 2.11.2 - 2026-10-13 -- **fix: HDMI-CEC on the Steam Machine no longer needs GitHub: when downloading Valve's CEC driver fails, Steamify uses the copy it carries (`patches/cros-ec-cec.c`), checked against the same pinned sha256** +- `124b424`, `f234c72` **fix: HDMI-CEC on the Steam Machine no longer needs GitHub: when downloading Valve's CEC driver fails, Steamify uses the copy it carries (`patches/cros-ec-cec.c`), checked against the same pinned sha256** -- **feat: the SteamOS conversion is offered on NVIDIA PCs again (GTX 16 / RTX 20 series or newer: Turing and later, the cards NVIDIA's open kernel driver supports): it builds and installs a patched gamescope from the recipe and patch Steamify carries (`patches/`, prepared in [steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia); gamescope 3.16.31, so a Steamify release builds the version it was tested with) (GBM-allocated scan-out buffers, NVIDIA's corrupted gaming-mode picture, gamescope#2309; a few minutes to build) and sets `gamescope_drm_gbm_scanout=1` for the session (`lib/gamescope-nvidia.sh`). It replaces "Gaming on NVIDIA", which is not offered any more (the kernel parameters, early modules, suspend memory and the 32-bit libraries come with the conversion on a supported card; a PC that had "Gaming on NVIDIA" on has it turned off when the conversion is turned on). Tested on an RTX 5080 (driver 615.78.08): Steam's gaming UI is clean with it and shows artifacts without. The package is pinned to one gamescope release: updating it is not automatic yet** +- `127b8cf`, `2811ecc`, `f3cd053`, `4325d80`, `03f9e87`, `5b5181f`, `06ffc8b`, `4d60dd2`, `0ba94b2` **feat: the SteamOS conversion is offered on NVIDIA PCs again (GTX 16 / RTX 20 series or newer: Turing and later, the cards NVIDIA's open kernel driver supports): it builds and installs a patched gamescope from the recipe and patch Steamify carries (`patches/`, prepared in [steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia); gamescope 3.16.31, so a Steamify release builds the version it was tested with) (GBM-allocated scan-out buffers, NVIDIA's corrupted gaming-mode picture, gamescope#2309; a few minutes to build) and sets `gamescope_drm_gbm_scanout=1` for the session (`lib/gamescope-nvidia.sh`). It replaces "Gaming on NVIDIA", which is not offered any more (the kernel parameters, early modules, suspend memory and the 32-bit libraries come with the conversion on a supported card; a PC that had "Gaming on NVIDIA" on has it turned off when the conversion is turned on). Tested on an RTX 5080 (driver 615.78.08): Steam's gaming UI is clean with it and shows artifacts without. The package is pinned to one gamescope release: updating it is not automatic yet** -- **feat: "Gaming on NVIDIA" also keeps video memory over suspend (`NVreg_PreserveVideoMemoryAllocations=1` in `/etc/modprobe.d/90-steamify-nvidia.conf`, the initramfs is rebuilt), enables `nvidia-suspend`/`nvidia-resume`/`nvidia-hibernate`, and installs `lib32-nvidia-utils` and `lib32-libxkbcommon` (32-bit games, the 32-bit MangoHud preload) on a supported card; off removes only what Steamify added. Untested on hardware yet** +- `ce4bc67` **feat: "Gaming on NVIDIA" also keeps video memory over suspend (`NVreg_PreserveVideoMemoryAllocations=1` in `/etc/modprobe.d/90-steamify-nvidia.conf`, the initramfs is rebuilt), enables `nvidia-suspend`/`nvidia-resume`/`nvidia-hibernate`, and installs `lib32-nvidia-utils` and `lib32-libxkbcommon` (32-bit games, the 32-bit MangoHud preload) on a supported card; off removes only what Steamify added. Untested on hardware yet** ## 2.11.1 - 2026-10-02 diff --git a/lib/gamescope-nvidia.sh b/lib/gamescope-nvidia.sh index dca71af..8a4e3c0 100644 --- a/lib/gamescope-nvidia.sh +++ b/lib/gamescope-nvidia.sh @@ -10,6 +10,14 @@ # Sourced by steamify.sh; not meant to be run on its own. GSN_PKG=steamify-gamescope-nvidia +# The package this Steamify release was tested with (the recipe in patches/ names the same version): built by CI in +# CachyOS's container and published as a release of steamify-gamescope-nvidia. A new pin: the release, its sha256, and +# patches/gamescope-nvidia.PKGBUILD's pkgver/pkgrel. +GSN_VERSION=3.16.31-1 +GSN_SHA256=9f20e5243866d1ddeb9ba0c6828bc7be1945f623f9a5d8094391f0df043002e1 +GSN_URL="${GSN_URL:-https://github.com/theupriser/steamify-gamescope-nvidia/releases/download/$GSN_VERSION}" +# Where the ISO leaves a copy of the same package, for installs without GitHub. +GSN_BACKUP_DIR="${GSN_BACKUP_DIR:-/usr/local/share/steamify/gamescope}" GSN_ENV_LINE='gamescope_drm_gbm_scanout=1' GSN_ENV_D="${GSN_ENV_D:-$HOME/.config/environment.d/99-steamify-gamescope-nvidia.conf}" GSN_SESSION_ENV="${GSN_SESSION_ENV:-$HOME/.config/gamescope-session/environment}" @@ -20,33 +28,80 @@ gsn_env_set() { [[ -f "$GSN_ENV_D" ]] && grep -qsx "$GSN_ENV_LINE" "$GSN_SESSION gsn_status() { gsn_package_installed && gsn_env_set; } -gsn_install_package() { - # Builds the package from the recipe and patch Steamify carries (patches/, so a Steamify release builds exactly the - # gamescope version it was tested with) and installs it. makepkg runs as the user, never as root, and downloads - # gamescope's sources (Valve's repository at the PKGBUILD's pkgver, and its submodules). The build needs a few minutes: - # gamescope compiles from source. --ask 4 lets pacman replace the stock gamescope it conflicts with. - gsn_package_installed && return 0 - info "Building the patched gamescope for NVIDIA (a few minutes)..." - sudo pacman -S --needed --noconfirm base-devel git || { err "Installing the build tools failed."; return 1; } - local dir pkg cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify" +gsn_package_current() { + # The pinned version is installed (a newer Steamify pins a newer one, which then installs over it). + [[ "$(pacman -Q "$GSN_PKG" 2>/dev/null | awk '{print $2}')" == "$GSN_VERSION" ]] +} + +gsn_sha_ok() { echo "$GSN_SHA256 $1" | sha256sum -c --quiet - >/dev/null 2>&1; } + +gsn_fetch_package() { + # The pinned, verified package, on stdout as a path: first from GitHub (built by CI in CachyOS's container), else the + # copy that came with the ISO. Both only count when their sha256 is the one pinned here: a Steamify release names + # exactly the package it was tested with, so an unchanged or swapped file is refused. + local cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify" file="$GSN_PKG-$GSN_VERSION-x86_64.pkg.tar.zst" backup + mkdir -p "$cache" || return 1 + if [[ -f "$cache/$file" ]] && gsn_sha_ok "$cache/$file"; then echo "$cache/$file"; return 0; fi + info "Downloading the patched gamescope (GitHub release $GSN_VERSION)..." >&2 + if curl -fsL --retry 2 --connect-timeout 15 --max-time 300 -o "$cache/$file.part" "$GSN_URL/$file" && + gsn_sha_ok "$cache/$file.part"; then + mv -f "$cache/$file.part" "$cache/$file" + echo "$cache/$file"; return 0 + fi + rm -f "$cache/$file.part" + warn "Downloading the patched gamescope failed (or its checksum didn't match)." >&2 + for backup in "$GSN_BACKUP_DIR/$file" "$cache/$file"; do + if [[ -f "$backup" ]] && gsn_sha_ok "$backup"; then + info "Using the copy that came with Steamify: $backup" >&2 + echo "$backup"; return 0 + fi + done + return 1 +} + +gsn_build_package() { + # Last resort: builds the package from the recipe and patch Steamify carries (patches/), as the user. It downloads + # gamescope's sources (Valve's repository at the PKGBUILD's pkgver, and its submodules) and compiles them: a few + # minutes. Prints the package's path. + local dir cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify" + info "Building the patched gamescope here instead (a few minutes)..." >&2 + sudo pacman -S --needed --noconfirm base-devel git >&2 || { err "Installing the build tools failed." >&2; return 1; } # On disk, not /tmp: the installer's chroot has a tmpfs there (RAM), and the build is 1-2 GB. mkdir -p "$cache" && dir="$(mktemp -d -p "$cache" gamescope-build.XXXXXX)" || return 1 patch_file gamescope-nvidia.PKGBUILD > "$dir/PKGBUILD" && patch_file gamescope-gbm-scanout.patch > "$dir/gamescope-gbm-scanout.patch" || { - err "Couldn't write the build files." + err "Couldn't write the build files." >&2 rm -rf "$dir"; return 1 } - if ! (cd "$dir" && makepkg -sf --noconfirm --nocheck); then - err "Building the patched gamescope failed (see above). The stock gamescope stays." - rm -rf "$dir"; return 1 - fi - pkg="$(ls "$dir"/"$GSN_PKG"-*.pkg.tar.* 2>/dev/null | grep -v -- '-debug-' | head -1)" - if [[ -z "$pkg" ]] || ! sudo pacman -U --noconfirm --ask 4 "$pkg"; then - err "Installing the patched gamescope failed. The stock gamescope stays." + if ! (cd "$dir" && makepkg -sf --noconfirm --nocheck >&2); then + err "Building the patched gamescope failed (see above)." >&2 rm -rf "$dir"; return 1 fi + # Moved out, so the build folder can go. + mv "$(ls "$dir"/"$GSN_PKG"-*.pkg.tar.* 2>/dev/null | grep -v -- '-debug-' | head -1)" "$cache/gamescope-local-build.pkg.tar.zst" || + { rm -rf "$dir"; return 1; } rm -rf "$dir" - ok "Patched gamescope installed." + echo "$cache/gamescope-local-build.pkg.tar.zst" +} + +gsn_install_package() { + # The patched gamescope, in this order, each step only when the one before failed: the pinned package from GitHub, the + # copy that came with the ISO, a build here. A package that downloaded fine but doesn't install (its libraries differ from + # this PC's) goes on to the build too. Nothing else changes before one of them is installed, so a failure leaves the PC as + # it was, with the stock gamescope. --ask 4 lets pacman replace the stock gamescope it conflicts with. + gsn_package_current && return 0 + local pkg + if pkg="$(gsn_fetch_package)" && sudo pacman -U --noconfirm --ask 4 "$pkg"; then + ok "Patched gamescope installed." + return 0 + fi + warn "The ready-made patched gamescope couldn't be installed." + if pkg="$(gsn_build_package)" && sudo pacman -U --noconfirm --ask 4 "$pkg"; then + ok "Patched gamescope built and installed." + return 0 + fi + err "The patched gamescope couldn't be installed. The stock gamescope stays." + return 1 } gsn_env_enable() { From 9e66790bad925846a209c96761fb515fe672909a Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 18:58:51 +0200 Subject: [PATCH 15/26] feat: the newest patched gamescope release first, the pinned one as the fallback, a newer release shows as an update --- CHANGELOG.md | 2 + TECHNICAL.md | 17 +++-- lib/gamescope-nvidia.sh | 138 +++++++++++++++++++++++++++++----------- lib/menu.sh | 2 + 4 files changed, 114 insertions(+), 45 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1e372a..9e5977e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ one per merged pull request. ## 2.11.2 - 2026-10-13 +- **feat: the patched gamescope is downloaded as the newest release of steamify-gamescope-nvidia (checked against that release's `.sha256`), a newer one than the installed package shows the SteamOS conversion as an update, and what this Steamify was tested with is the fallback: the pinned package (sha256 in Steamify), the copy the ISO leaves, a build here; the repository's workflow builds each release in CachyOS's container** + - `124b424`, `f234c72` **fix: HDMI-CEC on the Steam Machine no longer needs GitHub: when downloading Valve's CEC driver fails, Steamify uses the copy it carries (`patches/cros-ec-cec.c`), checked against the same pinned sha256** - `127b8cf`, `2811ecc`, `f3cd053`, `4325d80`, `03f9e87`, `5b5181f`, `06ffc8b`, `4d60dd2`, `0ba94b2` **feat: the SteamOS conversion is offered on NVIDIA PCs again (GTX 16 / RTX 20 series or newer: Turing and later, the cards NVIDIA's open kernel driver supports): it builds and installs a patched gamescope from the recipe and patch Steamify carries (`patches/`, prepared in [steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia); gamescope 3.16.31, so a Steamify release builds the version it was tested with) (GBM-allocated scan-out buffers, NVIDIA's corrupted gaming-mode picture, gamescope#2309; a few minutes to build) and sets `gamescope_drm_gbm_scanout=1` for the session (`lib/gamescope-nvidia.sh`). It replaces "Gaming on NVIDIA", which is not offered any more (the kernel parameters, early modules, suspend memory and the 32-bit libraries come with the conversion on a supported card; a PC that had "Gaming on NVIDIA" on has it turned off when the conversion is turned on). Tested on an RTX 5080 (driver 615.78.08): Steam's gaming UI is clean with it and shows artifacts without. The package is pinned to one gamescope release: updating it is not automatic yet** diff --git a/TECHNICAL.md b/TECHNICAL.md index 966df2f..a3572e6 100644 --- a/TECHNICAL.md +++ b/TECHNICAL.md @@ -243,19 +243,22 @@ Since 2.11.2 there is a second way: gamescope with GBM-allocated scan-out buffer without. The patch is nine commits of [farnoy/gamescope](https://github.com/farnoy/gamescope) (`nvidia-gbm-wayland`), carried in `patches/` (`gamescope-gbm-scanout.patch` and the recipe `gamescope-nvidia.PKGBUILD`, kept in sync with [steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia), where new gamescope versions are -prepared). `gsn_install_package` writes both into a temporary folder, builds the package there as the user (`makepkg -sf`: it -downloads Valve's gamescope at the PKGBUILD's `pkgver`, the version the patch was tested with, and its submodules; no checksums) and -installs it with `pacman -U --ask 4` (the package provides and conflicts with `gamescope`). A Steamify release therefore always -builds the gamescope version it was tested with. It is opt-in inside gamescope: `gamescope_drm_gbm_scanout=1` in +prepared). gamescope changes every few weeks, so the package is downloaded, not carried: `gsn_install_package` takes the +**newest release** of that repository (CI builds it in CachyOS's container; a person merges the version bump), checked against the +`.sha256` of the same release, and installs it with `pacman -U --ask 4` (the package provides and conflicts with `gamescope`). What +this Steamify release was tested with is the fallback, in this order: the pinned package (`GSN_VERSION`, `GSN_SHA256`: from GitHub, the +cache, or the copy the ISO leaves in `/usr/local/share/steamify/gamescope`), then a build here from the recipe and patch in `patches/` +(`makepkg -sf` as the user, in `~/.cache/steamify`; no checksums on gamescope's own sources). A package that downloaded fine but +doesn't install goes on to the next step; nothing changes before one of them is installed. A newer release than the installed package +shows the conversion as an update (`gsn_update_pending`, looked up at most every six hours, quiet offline). Simple files that don't +change (the power-off module, small patches) stay in `patches/` as they are. It is opt-in inside gamescope: `gamescope_drm_gbm_scanout=1` in `~/.config/gamescope-session/environment` and `~/.config/environment.d/99-steamify-gamescope-nvidia.conf`. The SteamOS conversion (`gaming_enable`) does this on every NVIDIA PC (`nvidia_present`: PCI vendor 0x10de, display class, its driver providing `nvidia_drm`), together with what "Gaming on NVIDIA" set up (on a supported card, `nvidia_supported`: GTX 16 / RTX 20 series or newer, Turing and later): the kernel parameters, the early modules, suspend memory, the 32-bit libraries (`nvidia_kernel_enable`, `nvidia_extras_enable`). So the SteamOS conversion is the one gaming option on NVIDIA now, and "Gaming on NVIDIA" (below) is not offered any more (`nvidia_available`); a PC that had it on keeps it until the conversion is turned on, which turns it off -(`nvidia_swap_out`). Turning the conversion off removes the setting and those settings, and keeps the packages. The package is -pinned to the gamescope release in the PKGBUILD: pacman does not update it, a newer one comes with a newer Steamify -(the bump is prepared in the repository above), and Steamify does not rebuild it by itself yet. Tested on an RTX 5080 only. +(`nvidia_swap_out`). Turning the conversion off removes the setting and those settings, and keeps the packages. Tested on an RTX 5080 only. Before 2.11.2, with an NVIDIA GPU the SteamOS conversion (`gaming`, and its options `boot`, `single`, `glyphs`) wasn't offered, unless it was already on. `nvidia` ("Gaming on NVIDIA", `lib/nvidia.sh`) took its place (both would start Steam at login): it installs `steam` when missing (recorded in state `nvidia`, removed again only then) and enables the user diff --git a/lib/gamescope-nvidia.sh b/lib/gamescope-nvidia.sh index 8a4e3c0..5815293 100644 --- a/lib/gamescope-nvidia.sh +++ b/lib/gamescope-nvidia.sh @@ -1,68 +1,122 @@ #!/bin/bash # gamescope's own gaming mode on NVIDIA: a patched gamescope that allocates its scan-out buffers with GBM, which cures -# the corrupted picture (https://github.com/ValveSoftware/gamescope/issues/2309). The patch and the build recipe are in -# patches/ (kept in sync with https://github.com/theupriser/steamify-gamescope-nvidia, where new gamescope versions are -# prepared); the package `steamify-gamescope-nvidia` is built here, on the PC, and replaces `gamescope` (it provides it). The patch is opt-in: gamescope reads `gamescope_drm_gbm_scanout=1` from its -# environment, which is set for the gaming session (gamescope-session's environment file, and environment.d). +# the corrupted picture (https://github.com/ValveSoftware/gamescope/issues/2309). The patch is opt-in: gamescope reads +# `gamescope_drm_gbm_scanout=1` from its environment, which is set for the gaming session (gamescope-session's +# environment file, and environment.d). +# +# gamescope changes every few weeks, so the package is not carried but downloaded: the newest release of +# https://github.com/theupriser/steamify-gamescope-nvidia (CI builds it in CachyOS's container, a person merges the +# version bump), and a newer one than the installed package shows as an update of the SteamOS conversion +# (`gsn_update_pending`). What this Steamify release was tested with is the fallback: the pinned package (sha256 below), +# a copy that came with the ISO, and last a build here from the recipe and patch in patches/. Simple files that don't change +# stay in patches/ and are used as they are. +# # Used by the SteamOS conversion (`gaming_enable`/`gaming_disable`) on every NVIDIA PC (`nvidia_present`); the kernel # parameters and the rest of lib/nvidia.sh's setup only on a supported card (`nvidia_supported`): GTX 16 / RTX 20 series or # newer (Turing and later, what NVIDIA's open kernel driver supports). Tested on an RTX 5080 only. # Sourced by steamify.sh; not meant to be run on its own. GSN_PKG=steamify-gamescope-nvidia -# The package this Steamify release was tested with (the recipe in patches/ names the same version): built by CI in -# CachyOS's container and published as a release of steamify-gamescope-nvidia. A new pin: the release, its sha256, and -# patches/gamescope-nvidia.PKGBUILD's pkgver/pkgrel. +GSN_RELEASES="${GSN_RELEASES:-https://github.com/theupriser/steamify-gamescope-nvidia/releases}" +# The package this Steamify release was tested with (patches/gamescope-nvidia.PKGBUILD names the same version): the +# fallback. A new pin: the release's tag, the package's sha256, and the PKGBUILD's pkgver/pkgrel. GSN_VERSION=3.16.31-1 GSN_SHA256=9f20e5243866d1ddeb9ba0c6828bc7be1945f623f9a5d8094391f0df043002e1 -GSN_URL="${GSN_URL:-https://github.com/theupriser/steamify-gamescope-nvidia/releases/download/$GSN_VERSION}" -# Where the ISO leaves a copy of the same package, for installs without GitHub. +# Where the ISO leaves a copy of the pinned package, for installs without GitHub. GSN_BACKUP_DIR="${GSN_BACKUP_DIR:-/usr/local/share/steamify/gamescope}" +# How long a look at GitHub for a newer release counts (seconds), so opening the menu doesn't ask every time. +GSN_CHECK_EVERY="${GSN_CHECK_EVERY:-21600}" GSN_ENV_LINE='gamescope_drm_gbm_scanout=1' GSN_ENV_D="${GSN_ENV_D:-$HOME/.config/environment.d/99-steamify-gamescope-nvidia.conf}" GSN_SESSION_ENV="${GSN_SESSION_ENV:-$HOME/.config/gamescope-session/environment}" gsn_package_installed() { pacman -Q "$GSN_PKG" >/dev/null 2>&1; } +gsn_installed_version() { pacman -Q "$GSN_PKG" 2>/dev/null | awk '{print $2}'; } + gsn_env_set() { [[ -f "$GSN_ENV_D" ]] && grep -qsx "$GSN_ENV_LINE" "$GSN_SESSION_ENV"; } gsn_status() { gsn_package_installed && gsn_env_set; } -gsn_package_current() { - # The pinned version is installed (a newer Steamify pins a newer one, which then installs over it). - [[ "$(pacman -Q "$GSN_PKG" 2>/dev/null | awk '{print $2}')" == "$GSN_VERSION" ]] +gsn_newer() { + # gsn_newer : version a is newer than b (pacman's own comparison). + [[ "$(vercmp "$1" "$2" 2>/dev/null)" == 1 ]] } -gsn_sha_ok() { echo "$GSN_SHA256 $1" | sha256sum -c --quiet - >/dev/null 2>&1; } +gsn_latest_tag() { + # The newest release's tag (-), from GitHub; nothing when it can't be reached or + # there is no release. Follows the redirect of /releases/latest: no API, no rate limit, no JSON. gsn_latest_tag [seconds] + local url + url="$(curl -fsL --connect-timeout 4 --max-time "${1:-10}" -o /dev/null -w '%{url_effective}' "$GSN_RELEASES/latest" 2>/dev/null)" || return 1 + url="${url##*/}" + [[ "$url" =~ ^[0-9][0-9A-Za-z._]*-[0-9]+$ ]] || return 1 + echo "$url" +} + +gsn_update_pending() { + # The patched gamescope is installed and GitHub has a newer release: the menu shows the conversion as an update. + # Looked up at most every GSN_CHECK_EVERY seconds (the answer is kept in the state), quickly, and silently when + # offline: no network is never a reason to show or hide anything. + gsn_package_installed || return 1 + local now checked latest + now="$(date +%s)"; checked="$(state_get gamescope_nvidia checked 0)" + if (( now - ${checked:-0} > GSN_CHECK_EVERY )); then + state_set gamescope_nvidia checked "$now" + latest="$(gsn_latest_tag 5)" && state_set gamescope_nvidia latest "$latest" + fi + latest="$(state_get gamescope_nvidia latest)" + [[ -n "$latest" ]] && gsn_newer "$latest" "$(gsn_installed_version)" +} + +gsn_sha_of() { + # The hash a release file is expected to have: the pinned one for the pinned version, else the .sha256 next to the + # package in the same release (it shows the download wasn't damaged, not who made it). + local tag="$1" file="$2" + if [[ "$tag" == "$GSN_VERSION" ]]; then echo "$GSN_SHA256"; return 0; fi + curl -fsL --connect-timeout 10 --max-time 30 "$GSN_RELEASES/download/$tag/$file.sha256" 2>/dev/null | awk 'NR==1 {print $1}' +} + +gsn_download() { + # gsn_download : the release's package, verified, in the cache; prints its path. + local tag="$1" cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify" file want got + file="$GSN_PKG-$tag-x86_64.pkg.tar.zst" + mkdir -p "$cache" || return 1 + want="$(gsn_sha_of "$tag" "$file")" + [[ "$want" =~ ^[0-9a-f]{64}$ ]] || return 1 + if [[ -f "$cache/$file" ]] && [[ "$(sha256sum "$cache/$file" | awk '{print $1}')" == "$want" ]]; then echo "$cache/$file"; return 0; fi + curl -fsL --retry 2 --connect-timeout 15 --max-time 300 -o "$cache/$file.part" "$GSN_RELEASES/download/$tag/$file" || { rm -f "$cache/$file.part"; return 1; } + got="$(sha256sum "$cache/$file.part" | awk '{print $1}')" + if [[ "$got" != "$want" ]]; then rm -f "$cache/$file.part"; return 1; fi + mv -f "$cache/$file.part" "$cache/$file" + echo "$cache/$file" +} gsn_fetch_package() { - # The pinned, verified package, on stdout as a path: first from GitHub (built by CI in CachyOS's container), else the - # copy that came with the ISO. Both only count when their sha256 is the one pinned here: a Steamify release names - # exactly the package it was tested with, so an unchanged or swapped file is refused. - local cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify" file="$GSN_PKG-$GSN_VERSION-x86_64.pkg.tar.zst" backup - mkdir -p "$cache" || return 1 - if [[ -f "$cache/$file" ]] && gsn_sha_ok "$cache/$file"; then echo "$cache/$file"; return 0; fi - info "Downloading the patched gamescope (GitHub release $GSN_VERSION)..." >&2 - if curl -fsL --retry 2 --connect-timeout 15 --max-time 300 -o "$cache/$file.part" "$GSN_URL/$file" && - gsn_sha_ok "$cache/$file.part"; then - mv -f "$cache/$file.part" "$cache/$file" - echo "$cache/$file"; return 0 + # The package to install, as a path, newest first: the newest release on GitHub (not older than the pinned one), else + # the pinned package (GitHub, the cache, or the copy that came with the ISO). Only files with the expected sha256 count. + local tag pkg cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify" file="$GSN_PKG-$GSN_VERSION-x86_64.pkg.tar.zst" copy + tag="$(gsn_latest_tag)" || tag="" + if [[ -n "$tag" && "$tag" != "$GSN_VERSION" ]] && gsn_newer "$tag" "$GSN_VERSION"; then + info "Downloading the newest patched gamescope ($tag)..." >&2 + if pkg="$(gsn_download "$tag")"; then echo "$pkg"; return 0; fi + warn "Downloading the newest patched gamescope ($tag) failed: using the version this Steamify was tested with ($GSN_VERSION)." >&2 fi - rm -f "$cache/$file.part" + info "Downloading the patched gamescope ($GSN_VERSION)..." >&2 + if pkg="$(gsn_download "$GSN_VERSION")"; then echo "$pkg"; return 0; fi warn "Downloading the patched gamescope failed (or its checksum didn't match)." >&2 - for backup in "$GSN_BACKUP_DIR/$file" "$cache/$file"; do - if [[ -f "$backup" ]] && gsn_sha_ok "$backup"; then - info "Using the copy that came with Steamify: $backup" >&2 - echo "$backup"; return 0 + for copy in "$GSN_BACKUP_DIR/$file" "$cache/$file"; do + if [[ -f "$copy" ]] && [[ "$(sha256sum "$copy" | awk '{print $1}')" == "$GSN_SHA256" ]]; then + info "Using the copy that came with Steamify: $copy" >&2 + echo "$copy"; return 0 fi done return 1 } gsn_build_package() { - # Last resort: builds the package from the recipe and patch Steamify carries (patches/), as the user. It downloads - # gamescope's sources (Valve's repository at the PKGBUILD's pkgver, and its submodules) and compiles them: a few - # minutes. Prints the package's path. + # Last resort: builds the pinned package from the recipe and patch Steamify carries (patches/), as the user. It + # downloads gamescope's sources (Valve's repository at the PKGBUILD's pkgver, and its submodules) and compiles them: a + # few minutes. Prints the package's path. local dir cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify" info "Building the patched gamescope here instead (a few minutes)..." >&2 sudo pacman -S --needed --noconfirm base-devel git >&2 || { err "Installing the build tools failed." >&2; return 1; } @@ -85,17 +139,25 @@ gsn_build_package() { } gsn_install_package() { - # The patched gamescope, in this order, each step only when the one before failed: the pinned package from GitHub, the - # copy that came with the ISO, a build here. A package that downloaded fine but doesn't install (its libraries differ from - # this PC's) goes on to the build too. Nothing else changes before one of them is installed, so a failure leaves the PC as - # it was, with the stock gamescope. --ask 4 lets pacman replace the stock gamescope it conflicts with. - gsn_package_current && return 0 - local pkg + # The patched gamescope, newest first, each step only when the one before failed: the newest release from GitHub, the + # pinned package (GitHub, cache or the copy that came with the ISO), a build here. A package that downloaded fine but + # doesn't install (its libraries differ from this PC's) goes on to the next step too. Nothing else changes before one of + # them is installed, so a failure leaves the PC as it was, with what it had. --ask 4 lets pacman replace the stock + # gamescope it conflicts with, and an older patched one. + local pkg latest have + have="$(gsn_installed_version)" + latest="$(gsn_latest_tag)" || latest="" + # Already the newest (or, offline, the pinned version or newer): nothing to do. + if [[ -n "$have" ]]; then + if [[ -n "$latest" ]] && ! gsn_newer "$latest" "$have"; then return 0; fi + if [[ -z "$latest" ]] && ! gsn_newer "$GSN_VERSION" "$have"; then return 0; fi + fi if pkg="$(gsn_fetch_package)" && sudo pacman -U --noconfirm --ask 4 "$pkg"; then ok "Patched gamescope installed." return 0 fi warn "The ready-made patched gamescope couldn't be installed." + [[ -n "$have" ]] && { warn "The installed one ($have) stays."; return 0; } if pkg="$(gsn_build_package)" && sudo pacman -U --noconfirm --ask 4 "$pkg"; then ok "Patched gamescope built and installed." return 0 diff --git a/lib/menu.sh b/lib/menu.sh index 08ca8ff..cd2b12e 100644 --- a/lib/menu.sh +++ b/lib/menu.sh @@ -116,6 +116,8 @@ feature_outdated() { # "Gaming on NVIDIA" is on: the SteamOS conversion replaces it, as an update of what the PC has (lib/nvidia.sh). [[ "$1" == gaming ]] && nvidia_migration_pending && return 0 [[ "${CURRENT[$1]:-0}" == 1 ]] || return 1 + # NVIDIA: a newer patched gamescope is out (lib/gamescope-nvidia.sh): a normal run installs it. + [[ "$1" == gaming ]] && nvidia_present && gsn_update_pending && return 0 have="$(state_get features "$1" "$FEATURE_BASELINE")" [[ "$have" == off ]] && have="$FEATURE_BASELINE" want="${FEATURE_VERSION[$1]:-$FEATURE_BASELINE}" From 3ebb8d3bc972f7d910ce40c4fb5a063d96ecbefa Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 19:03:23 +0200 Subject: [PATCH 16/26] fix: keep python-hidapi: a placeholder provides python-hid for jupiter-hw-support --- CHANGELOG.md | 2 ++ lib/packages.sh | 25 +++++++++++++++++++++++++ patches/README.md | 1 + patches/python-hid-shim.PKGBUILD | 17 +++++++++++++++++ 4 files changed, 45 insertions(+) create mode 100644 patches/python-hid-shim.PKGBUILD diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e5977e..9e7359b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ one per merged pull request. ## 2.11.2 - 2026-10-13 +- **fix: a PC that keeps `python-hidapi` (liquidctl needs it) can use the SteamOS conversion: jupiter-hw-support, which gamescope-session-cachyos depends on, wants `python-hid`, which conflicts with it and stopped the package install. Steamify builds and installs an empty placeholder package that provides `python-hid` first (`patches/python-hid-shim.PKGBUILD`); only the Steam Deck controller firmware updater uses it** + - **feat: the patched gamescope is downloaded as the newest release of steamify-gamescope-nvidia (checked against that release's `.sha256`), a newer one than the installed package shows the SteamOS conversion as an update, and what this Steamify was tested with is the fallback: the pinned package (sha256 in Steamify), the copy the ISO leaves, a build here; the repository's workflow builds each release in CachyOS's container** - `124b424`, `f234c72` **fix: HDMI-CEC on the Steam Machine no longer needs GitHub: when downloading Valve's CEC driver fails, Steamify uses the copy it carries (`patches/cros-ec-cec.c`), checked against the same pinned sha256** diff --git a/lib/packages.sh b/lib/packages.sh index 14164d0..d16a45e 100644 --- a/lib/packages.sh +++ b/lib/packages.sh @@ -58,6 +58,30 @@ bootstrap_yay() { fi } +python_hid_shim_ensure() { + # jupiter-hw-support (a dependency of gamescope-session-cachyos) wants python-hid, which conflicts with python-hidapi, and + # a PC can need python-hidapi (liquidctl does). Only Valve's Steam Deck controller firmware updater uses python-hid, which + # a PC doesn't run: so a placeholder package that provides python-hid keeps python-hidapi and satisfies the dependency + # (also at later updates, which a one-time --assume-installed wouldn't). It stays when the conversion goes off: + # jupiter-hw-support, which stays, depends on it. + pacman -Q python-hidapi >/dev/null 2>&1 || return 0 + pacman -Q python-hid steamify-python-hid-shim >/dev/null 2>&1 && return 0 + local dir pkg cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify" + warn "python-hidapi is installed (liquidctl and others need it) and conflicts with python-hid, which Steam Deck's tools ask for: keeping python-hidapi, with a small placeholder package for python-hid." + sudo pacman -S --needed --noconfirm base-devel >/dev/null || { err "Installing the build tools failed."; return 1; } + mkdir -p "$cache" && dir="$(mktemp -d -p "$cache" hid-shim.XXXXXX)" || return 1 + patch_file python-hid-shim.PKGBUILD > "$dir/PKGBUILD" || { rm -rf "$dir"; return 1; } + if ! (cd "$dir" && makepkg -f --noconfirm >/dev/null) || + ! pkg="$(ls "$dir"/steamify-python-hid-shim-*.pkg.tar.* 2>/dev/null | head -1)" || + ! sudo pacman -U --noconfirm "$pkg"; then + rm -rf "$dir" + err "Couldn't set up the python-hid placeholder: python-hidapi and python-hid conflict, so the packages can't be installed." + return 1 + fi + rm -rf "$dir" + ok "python-hidapi kept; python-hid is covered by a placeholder." +} + install_required_packages() { # Step 2: gamescope/Steam and the desktop helpers the rest of the setup uses. local -a MISSING @@ -65,6 +89,7 @@ install_required_packages() { mapfile -t MISSING < <(pacman -T gamescope-session-cachyos steam mangohud xterm ttf-liberation wqy-zenhei plasma-keyboard) if [[ ${#MISSING[@]} -gt 0 ]]; then + python_hid_shim_ensure || return 1 info "Installing missing packages: ${MISSING[*]}" sudo pacman -S --needed --noconfirm "${MISSING[@]}" || { err "Package installation failed."; return 1; } else diff --git a/patches/README.md b/patches/README.md index cfbfd6c..e63c914 100644 --- a/patches/README.md +++ b/patches/README.md @@ -19,3 +19,4 @@ read and reviewed on their own. `lib/*.sh` reads them with `patch_file | `gamescope-gbm-scanout.patch` | `lib/gamescope-nvidia.sh` (gamescope on NVIDIA) | gamescope 3.16.31 patch: scan-out buffers allocated with GBM (opt-in, `gamescope_drm_gbm_scanout=1`), which cures the corrupted picture on NVIDIA; from farnoy/gamescope, see the header of the file | | `gamescope-nvidia.PKGBUILD` | `lib/gamescope-nvidia.sh` (gamescope on NVIDIA) | The recipe for the patched gamescope package (`steamify-gamescope-nvidia`, provides and conflicts with `gamescope`): Valve's gamescope at `pkgver` plus `gamescope-gbm-scanout.patch`; written with the patch to a temporary folder and built with `makepkg` | | `cros-ec-cec.c` | `lib/cec.sh` (HDMI-CEC) | Valve's Steam Machine CEC driver (GPL-2.0+, from evlaV/linux-integration at the pinned commit): the backup when downloading it from GitHub fails; used only if its sha256 equals `CEC_DRIVER_SHA256` (a new pin needs a new copy) | +| `python-hid-shim.PKGBUILD` | `lib/packages.sh` (required packages) | An empty package that provides `python-hid`, for PCs that keep `python-hidapi` (they conflict; jupiter-hw-support, a dependency of gamescope-session-cachyos, wants python-hid, only the Steam Deck controller updater uses it): built with `makepkg` and installed before the conversion's packages | diff --git a/patches/python-hid-shim.PKGBUILD b/patches/python-hid-shim.PKGBUILD new file mode 100644 index 0000000..aac96f8 --- /dev/null +++ b/patches/python-hid-shim.PKGBUILD @@ -0,0 +1,17 @@ +# Maintainer: theupriser +# An empty package that only tells pacman "python-hid is there". For a PC that keeps python-hidapi (liquidctl needs it): +# the real python-hid conflicts with it, and jupiter-hw-support (a dependency of gamescope-session-cachyos) wants python-hid. +# Only Valve's Steam Deck controller firmware updater in jupiter-hw-support uses it, which a PC doesn't run. +# Steamify (lib/packages.sh) builds it with makepkg and installs it before the conversion's packages. +pkgname=steamify-python-hid-shim +pkgver=1 +pkgrel=1 +pkgdesc='Placeholder: python-hid for PCs that keep python-hidapi (they conflict)' +arch=(any) +license=(MIT) +depends=(python-hidapi) +provides=('python-hid=99') + +package() { + : +} From a73d302869abaec3eabfb272b2ebe1d3a0df31e7 Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 19:05:56 +0200 Subject: [PATCH 17/26] fix: sub-options are skipped when their parent failed --- CHANGELOG.md | 2 ++ lib/backend.sh | 5 +++++ lib/menu.sh | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e7359b..f088212 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ one per merged pull request. ## 2.11.2 - 2026-10-13 +- **fix: when an option fails, its sub-options are not applied any more (a failed conversion used to leave its "Boot into the desktop", silent start and icons on without it)** + - **fix: a PC that keeps `python-hidapi` (liquidctl needs it) can use the SteamOS conversion: jupiter-hw-support, which gamescope-session-cachyos depends on, wants `python-hid`, which conflicts with it and stopped the package install. Steamify builds and installs an empty placeholder package that provides `python-hid` first (`patches/python-hid-shim.PKGBUILD`); only the Steam Deck controller firmware updater uses it** - **feat: the patched gamescope is downloaded as the newest release of steamify-gamescope-nvidia (checked against that release's `.sha256`), a newer one than the installed package shows the SteamOS conversion as an update, and what this Steamify was tested with is the fallback: the pinned package (sha256 in Steamify), the copy the ISO leaves, a build here; the repository's workflow builds each release in CachyOS's container** diff --git a/lib/backend.sh b/lib/backend.sh index 9d523eb..f987a7c 100644 --- a/lib/backend.sh +++ b/lib/backend.sh @@ -185,6 +185,11 @@ backend_apply() { if backend_run_component "$c" disable; then feature_record "$c" disable; else failed+=("$c"); fi done for c in "${TO_ENABLE[@]}"; do + # A sub-option of something that just failed isn't applied: it would be left on without its parent. + if [[ -n "${PARENT[$c]:-}" && " ${failed[*]:-} " == *" ${PARENT[$c]} "* ]]; then + warn "Skipping ${LABEL[$c]%%:*}: ${LABEL[${PARENT[$c]}]%%:*} didn't work." + continue + fi if backend_run_component "$c" enable; then is_action "$c" || feature_record "$c" enable; else failed+=("$c"); fi done feature_record_unticked diff --git a/lib/menu.sh b/lib/menu.sh index cd2b12e..66206f9 100644 --- a/lib/menu.sh +++ b/lib/menu.sh @@ -511,6 +511,11 @@ apply_changes() { if "${c}_disable"; then feature_record "$c" disable; else failed+=("$c"); fi done for c in "${TO_ENABLE[@]}"; do + # A sub-option of something that just failed isn't applied: it would be left on without its parent. + if [[ -n "${PARENT[$c]:-}" && " ${failed[*]:-} " == *" ${PARENT[$c]} "* ]]; then + warn "Skipping ${LABEL[$c]%%:*}: ${LABEL[${PARENT[$c]}]%%:*} didn't work." + continue + fi if [[ "$c" == boot ]]; then echo; echo -e "${c_bold}Boot into: desktop${c_reset}" elif is_action "$c"; then echo; echo -e "${c_bold}Running: ${LABEL[$c]%%:*}${c_reset}" else echo; echo -e "${c_bold}Turning on: ${LABEL[$c]}${c_reset}"; fi From 5dc39b56c2f19d0d6a26b06bf163f16d49afeb0d Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 19:06:10 +0200 Subject: [PATCH 18/26] fix: the skipped sub-option is reported as an app event, and counts as not applied --- lib/backend.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/backend.sh b/lib/backend.sh index f987a7c..68e4556 100644 --- a/lib/backend.sh +++ b/lib/backend.sh @@ -187,7 +187,8 @@ backend_apply() { for c in "${TO_ENABLE[@]}"; do # A sub-option of something that just failed isn't applied: it would be left on without its parent. if [[ -n "${PARENT[$c]:-}" && " ${failed[*]:-} " == *" ${PARENT[$c]} "* ]]; then - warn "Skipping ${LABEL[$c]%%:*}: ${LABEL[${PARENT[$c]}]%%:*} didn't work." + backend_event log "\"id\":$(json_str "$c"),\"line\":$(json_str "Skipped: ${LABEL[${PARENT[$c]}]%%:*} didn't work.")" + failed+=("$c") continue fi if backend_run_component "$c" enable; then is_action "$c" || feature_record "$c" enable; else failed+=("$c"); fi From 46e46013898b99e6f17633c8d1d61e4b3a2f8ceb Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 19:09:28 +0200 Subject: [PATCH 19/26] fix: the conversion removes single user mode's desktop autologin, which pinned the Plasma session --- CHANGELOG.md | 2 ++ lib/login-manager.sh | 4 ++++ lib/single-user.sh | 9 +++++++++ 3 files changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f088212..c740638 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ one per merged pull request. ## 2.11.2 - 2026-10-13 +- **fix: on an NVIDIA PC that had single user mode on before the SteamOS conversion, "Return to Gaming Mode" and the boot choice work again: single user mode's desktop autologin (`zzz-steamify-autologin.conf`, read last) pinned the Plasma session; the conversion removes it, and turning the conversion off sets it up again** + - **fix: when an option fails, its sub-options are not applied any more (a failed conversion used to leave its "Boot into the desktop", silent start and icons on without it)** - **fix: a PC that keeps `python-hidapi` (liquidctl needs it) can use the SteamOS conversion: jupiter-hw-support, which gamescope-session-cachyos depends on, wants `python-hid`, which conflicts with it and stopped the package install. Steamify builds and installs an empty placeholder package that provides `python-hid` first (`patches/python-hid-shim.PKGBUILD`); only the Steam Deck controller firmware updater uses it** diff --git a/lib/login-manager.sh b/lib/login-manager.sh index 2781f71..c8ec2a1 100644 --- a/lib/login-manager.sh +++ b/lib/login-manager.sh @@ -109,6 +109,8 @@ gaming_enable() { install_session_sync ;; esac + # (NVIDIA with single user mode from before the conversion: its desktop autologin would pin the Plasma session.) + single_login_release create_desktop_shortcut steam_enable os_name_enable || return 1 @@ -127,6 +129,8 @@ gaming_disable() { gsn_disable krevert gaming os_name_disable + # NVIDIA with single user mode still on: nothing else logs in by itself any more. + nvidia_present && single_status && single_login_enable ok "The PC boots to the normal login screen again (from the next boot)." } diff --git a/lib/single-user.sh b/lib/single-user.sh index 2adc95c..6087cc8 100644 --- a/lib/single-user.sh +++ b/lib/single-user.sh @@ -140,6 +140,15 @@ EOF remove_sddm_base_autologin } +single_login_release() { + # The SteamOS conversion logs in by itself, and picks the session (gamescope, or the desktop with "Boot into"): the + # desktop autologin above, which sorts last, would pin the Plasma session and "Return to Gaming Mode" would open KDE + # again. Called when the conversion is turned on; turning it off sets it up again (gaming_disable). + [[ -f "$SINGLE_AUTOLOGIN" ]] || return 0 + info "The SteamOS conversion logs in by itself: removing the desktop autologin of single user mode." + sudo rm -f "$SINGLE_AUTOLOGIN" +} + single_login_disable() { [[ -f "$SINGLE_AUTOLOGIN" ]] || return 0 sudo rm -f "$SINGLE_AUTOLOGIN" From 5b901ea1b714ca776923de4a2e0f7c91164275f0 Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 19:59:15 +0200 Subject: [PATCH 20/26] feat: the gaming session on NVIDIA runs on the display's own mode, Steam's UI at its size; pin 3.16.31-2 --- AGENTS.md | 14 +++++--- CHANGELOG.md | 2 ++ lib/gamescope-nvidia.sh | 46 +++++++++++++++++++++++-- lib/menu.sh | 2 +- patches/README.md | 2 ++ patches/gamescope-display-wrapper.sh | 51 ++++++++++++++++++++++++++++ patches/gamescope-nvidia.PKGBUILD | 12 ++++--- patches/gamescope-ui-native.patch | 39 +++++++++++++++++++++ 8 files changed, 155 insertions(+), 13 deletions(-) create mode 100644 patches/gamescope-display-wrapper.sh create mode 100644 patches/gamescope-ui-native.patch diff --git a/AGENTS.md b/AGENTS.md index c18c532..aff9ea2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -48,11 +48,15 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine `_available` is checked via `component_available` (e.g. `machine` only on Fremont). Turn-on order is `COMPONENTS` order, turn-off reverse; `gaming` must stay first. Dependencies live in `toggle_component`. -- **NVIDIA** (`lib/nvidia.sh`): gamescope's session is broken on NVIDIA, so the SteamOS conversion (`gaming`, `boot`, `single`, - `glyphs`) is hidden there (unless already on) and `nvidia` + its sub-option `bigpicture` ("Gaming on NVIDIA") replace it: - Steam on the Plasma desktop, started at login. Never reintroduce a gamescope session for NVIDIA without re-testing on the - hardware (notes: steamify-cachyos-dev, `nvidia/`). It can't be tested without the hardware: keep the branch behind - `.no-release-yet` until it was. +- **NVIDIA** (`lib/gamescope-nvidia.sh`, `lib/nvidia.sh`): since 2.11.2 the SteamOS conversion (`gaming` and its options) runs on + NVIDIA PCs with a patched gamescope (GBM scan-out: gamescope#2309; Steam's UI kept at the display's size), downloaded as the + newest release of theupriser/steamify-gamescope-nvidia, with the pinned package (`GSN_VERSION`, `GSN_SHA256`), the copy the ISO + leaves, and a build here (`patches/gamescope-nvidia.PKGBUILD` + the two patches) as the fallback. "Gaming on NVIDIA" (`nvidia`, + `bigpicture`, `nvsilent`) isn't offered any more (`nvidia_available`); turning the conversion on turns it off (`nvidia_swap_out`). + A new pin = the release's tag + its sha256 in `lib/gamescope-nvidia.sh` and the PKGBUILD's pkgver/pkgrel, copied from the + repository (the patches in `patches/` must stay identical to that repository's). Steam must keep running with `-steamos3` + (without it games don't launch in gaming mode and the settings pages go): never "fix" the UI size by dropping flags or by + `XWAYLAND_COUNT`. Tested on an RTX 5080 only; keep the branch behind `.no-release-yet` until the whole flow ran on hardware. - **Feature versions.** Set `FEATURE_VERSION[]` (`lib/menu.sh`) to the new `VERSION` whenever what `_enable` sets up changes (a new component gets one too): installs recorded with an older version diff --git a/CHANGELOG.md b/CHANGELOG.md index c740638..115e689 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ one per merged pull request. ## 2.11.2 - 2026-10-13 +- **feat: on NVIDIA the gaming session runs on the display's own mode and Steam's interface at its size: a second gamescope patch (`gamescope-ui-native.patch`, release `3.16.31-2` of steamify-gamescope-nvidia, now the pin) keeps Steam's UI X server at the output size when Steam (with `-steamos3`) asks for 1920x1080, and a wrapper (`gamescope-display-wrapper.sh`, set up by the conversion with a drop-in of `gamescope-session.service`) starts gamescope on the mode KDE has saved for the connected display, else the biggest mode at the highest refresh rate: before, gaming mode ran at the display's preferred mode (60 Hz on many monitors) with a 1080p Steam UI. Tested on an RTX 5080, 3440x1440@175: widescreen, sharp, a Proton game starts** + - **fix: on an NVIDIA PC that had single user mode on before the SteamOS conversion, "Return to Gaming Mode" and the boot choice work again: single user mode's desktop autologin (`zzz-steamify-autologin.conf`, read last) pinned the Plasma session; the conversion removes it, and turning the conversion off sets it up again** - **fix: when an option fails, its sub-options are not applied any more (a failed conversion used to leave its "Boot into the desktop", silent start and icons on without it)** diff --git a/lib/gamescope-nvidia.sh b/lib/gamescope-nvidia.sh index 5815293..4d2b0ad 100644 --- a/lib/gamescope-nvidia.sh +++ b/lib/gamescope-nvidia.sh @@ -20,8 +20,8 @@ GSN_PKG=steamify-gamescope-nvidia GSN_RELEASES="${GSN_RELEASES:-https://github.com/theupriser/steamify-gamescope-nvidia/releases}" # The package this Steamify release was tested with (patches/gamescope-nvidia.PKGBUILD names the same version): the # fallback. A new pin: the release's tag, the package's sha256, and the PKGBUILD's pkgver/pkgrel. -GSN_VERSION=3.16.31-1 -GSN_SHA256=9f20e5243866d1ddeb9ba0c6828bc7be1945f623f9a5d8094391f0df043002e1 +GSN_VERSION=3.16.31-2 +GSN_SHA256=3b981bed4dfdac383d22b8c22feaef191c2f2863bccf5676d1ec959c2c5ee3a3 # Where the ISO leaves a copy of the pinned package, for installs without GitHub. GSN_BACKUP_DIR="${GSN_BACKUP_DIR:-/usr/local/share/steamify/gamescope}" # How long a look at GitHub for a newer release counts (seconds), so opening the menu doesn't ask every time. @@ -123,7 +123,8 @@ gsn_build_package() { # On disk, not /tmp: the installer's chroot has a tmpfs there (RAM), and the build is 1-2 GB. mkdir -p "$cache" && dir="$(mktemp -d -p "$cache" gamescope-build.XXXXXX)" || return 1 patch_file gamescope-nvidia.PKGBUILD > "$dir/PKGBUILD" && - patch_file gamescope-gbm-scanout.patch > "$dir/gamescope-gbm-scanout.patch" || { + patch_file gamescope-gbm-scanout.patch > "$dir/gamescope-gbm-scanout.patch" && + patch_file gamescope-ui-native.patch > "$dir/gamescope-ui-native.patch" || { err "Couldn't write the build files." >&2 rm -rf "$dir"; return 1 } @@ -179,6 +180,43 @@ gsn_env_disable() { return 0 } +# --- The session starts gamescope on the display's own mode +# +# gamescope-session starts gamescope without a size or a refresh rate, so it takes the display's *preferred* mode, which +# many monitors declare as 60 Hz while the desktop runs them at their highest. patches/gamescope-display-wrapper.sh (put +# first in the gaming session's PATH by a drop-in of gamescope-session.service) starts it on the mode KDE has saved for +# the connected display, else the biggest mode at the highest refresh rate, read at every session start. +GSN_DISPLAY_WRAPPER="${GSN_DISPLAY_WRAPPER:-$STEAMIFY_BIN/gamescope}" +GSN_DISPLAY_DROPIN="${GSN_DISPLAY_DROPIN:-$HOME/.config/systemd/user/gamescope-session.service.d/steamify-display.conf}" + +gsn_display_status() { [[ -x "$GSN_DISPLAY_WRAPPER" && -f "$GSN_DISPLAY_DROPIN" ]]; } + +gsn_display_pending() { + # The patched gamescope is in use but the session still starts it on the display's preferred mode: a normal run sets it up. + gsn_package_installed && gsn_env_set && ! gsn_display_status +} + +gsn_display_enable() { + patch_file gamescope-display-wrapper.sh | install_executable "$GSN_DISPLAY_WRAPPER" 755 || return 1 + mkdir -p "$(dirname "$GSN_DISPLAY_DROPIN")" + cat > "$GSN_DISPLAY_DROPIN" << EOF +# Steamify: the gaming session starts gamescope on the display's own mode (see lib/gamescope-nvidia.sh). Turning the +# SteamOS conversion off removes this file. +[Service] +ExecStart= +ExecStart=/usr/bin/bash -c 'PATH="$(dirname "$GSN_DISPLAY_WRAPPER"):\$PATH" exec /usr/lib/steamos/gamescope-session' +EOF + user_systemctl daemon-reload +} + +gsn_display_disable() { + # Only our own files: the wrapper is recognised by its first comment line. + grep -qs "^# Steamify: gamescope-session starts gamescope" "$GSN_DISPLAY_WRAPPER" && rm -f "$GSN_DISPLAY_WRAPPER" + [[ -f "$GSN_DISPLAY_DROPIN" ]] && rm -f "$GSN_DISPLAY_DROPIN" && rmdir "$(dirname "$GSN_DISPLAY_DROPIN")" 2>/dev/null + user_systemctl daemon-reload + return 0 +} + gsn_enable() { # Only on a supported NVIDIA card; elsewhere the stock gamescope is right. nvidia_present || return 0 @@ -191,6 +229,7 @@ gsn_enable() { nvidia_extras_enable || return 1 gsn_install_package || return 1 gsn_env_enable + gsn_display_enable || warn "Couldn't set up the display mode for gaming mode: gamescope takes the display's preferred mode." ok "gamescope draws NVIDIA's picture through GBM (gamescope_drm_gbm_scanout=1) from the next gaming mode start." } @@ -198,6 +237,7 @@ gsn_disable() { # The setting goes, and what nvidia_*_enable added; the packages stay (patched gamescope, 32-bit libraries), like # the other packages of the conversion (steam, gamescope-session-cachyos). gsn_env_disable + gsn_display_disable nvidia_present || return 0 nvidia_extras_disable nvidia_kernel_disable diff --git a/lib/menu.sh b/lib/menu.sh index 66206f9..a58d110 100644 --- a/lib/menu.sh +++ b/lib/menu.sh @@ -117,7 +117,7 @@ feature_outdated() { [[ "$1" == gaming ]] && nvidia_migration_pending && return 0 [[ "${CURRENT[$1]:-0}" == 1 ]] || return 1 # NVIDIA: a newer patched gamescope is out (lib/gamescope-nvidia.sh): a normal run installs it. - [[ "$1" == gaming ]] && nvidia_present && gsn_update_pending && return 0 + [[ "$1" == gaming ]] && nvidia_present && { gsn_update_pending || gsn_display_pending; } && return 0 have="$(state_get features "$1" "$FEATURE_BASELINE")" [[ "$have" == off ]] && have="$FEATURE_BASELINE" want="${FEATURE_VERSION[$1]:-$FEATURE_BASELINE}" diff --git a/patches/README.md b/patches/README.md index e63c914..ae5b89c 100644 --- a/patches/README.md +++ b/patches/README.md @@ -20,3 +20,5 @@ read and reviewed on their own. `lib/*.sh` reads them with `patch_file | `gamescope-nvidia.PKGBUILD` | `lib/gamescope-nvidia.sh` (gamescope on NVIDIA) | The recipe for the patched gamescope package (`steamify-gamescope-nvidia`, provides and conflicts with `gamescope`): Valve's gamescope at `pkgver` plus `gamescope-gbm-scanout.patch`; written with the patch to a temporary folder and built with `makepkg` | | `cros-ec-cec.c` | `lib/cec.sh` (HDMI-CEC) | Valve's Steam Machine CEC driver (GPL-2.0+, from evlaV/linux-integration at the pinned commit): the backup when downloading it from GitHub fails; used only if its sha256 equals `CEC_DRIVER_SHA256` (a new pin needs a new copy) | | `python-hid-shim.PKGBUILD` | `lib/packages.sh` (required packages) | An empty package that provides `python-hid`, for PCs that keep `python-hidapi` (they conflict; jupiter-hw-support, a dependency of gamescope-session-cachyos, wants python-hid, only the Steam Deck controller updater uses it): built with `makepkg` and installed before the conversion's packages | +| `gamescope-ui-native.patch` | `lib/gamescope-nvidia.sh` (gamescope on NVIDIA) | Small patch after the GBM one: keeps Steam's UI X server at the display's size when Steam (with `-steamos3`) asks for 1920x1080; `gamescope_xwayland_ui_native=0` turns it off | +| `gamescope-display-wrapper.sh` | `lib/gamescope-nvidia.sh` (gamescope on NVIDIA) | Installed as `gamescope` in Steamify's bin folder and put first in the gaming session's PATH: starts gamescope on the mode KDE has saved for the connected display, else the biggest mode at the highest refresh rate (modetest + `kwinoutputconfig.json`) | diff --git a/patches/gamescope-display-wrapper.sh b/patches/gamescope-display-wrapper.sh new file mode 100644 index 0000000..5a632be --- /dev/null +++ b/patches/gamescope-display-wrapper.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# Steamify: gamescope-session starts gamescope without a size or a refresh rate, so it takes the display's *preferred* mode, +# which many monitors declare as 60 Hz (the faster modes sit in an extension block of the EDID). This starts it the way the +# desktop runs that display: the mode KDE has saved for the connected display (System Settings > Display), when the display +# still has it, else its biggest mode at the highest refresh rate. +# Read at every session start (modetest, part of libdrm which gamescope needs, and KDE's ~/.config/kwinoutputconfig.json), so +# changing the resolution in KDE, another monitor or a TV just works. Anything unclear (no modetest output, no modes, more than +# one display connected: gamescope chooses which one it uses) leaves gamescope's own choice alone. +real=/usr/bin/gamescope + +modes() { + # One line per mode of every connected connector: " " + local m + for m in nvidia-drm amdgpu i915 xe nouveau radeon; do + timeout 10 modetest -M "$m" -c 2>/dev/null | awk ' + /^[0-9]+[ \t]+[0-9]+[ \t]+(connected|disconnected|unknown)/ { conn = ($3 == "connected") ? $4 : ""; next } + conn != "" && /^[ \t]+#[0-9]+ [0-9]+x[0-9]+ [0-9.]+ / && !/interlace/ { + split($2, wh, "x"); printf "%s %d %d %.0f\n", conn, wh[1], wh[2], $3 + }' + done +} + +kde_mode() { + # kde_mode : " " as KDE has it saved for that connector, or nothing. + python3 -I - "$1" "${XDG_CONFIG_HOME:-$HOME/.config}/kwinoutputconfig.json" 2>/dev/null << 'EOF' +import json, sys +try: + for block in json.load(open(sys.argv[2])): + if block.get("name") == "outputs": + for o in block.get("data", []): + m = o.get("mode") + if o.get("connectorName") == sys.argv[1] and m: + print(m["width"], m["height"], round(m["refreshRate"] / 1000)) +except Exception: + pass +EOF +} + +args=() +all="$(modes)" +conn="$(awk '{print $1}' <<< "$all" | sort -u)" +if [[ -n "$conn" && "$(wc -l <<< "$conn")" == 1 ]]; then + read -r w h r <<< "$(kde_mode "$conn")" + # KDE's mode only counts when the display really has it (a refresh rate within 1 Hz). + if [[ -z "${w:-}" ]] || ! awk -v w="$w" -v h="${h:-0}" -v r="${r:-0}" '$2 == w && $3 == h && ($4 - r < 2 && r - $4 < 2) {f = 1} END {exit !f}' <<< "$all"; then + read -r _ w h r < <(awk '{print $2 * $3, $2, $3, $4}' <<< "$all" | sort -k1,1nr -k4,4nr | head -1 | awk '{print "x", $2, $3, $4}') + fi + [[ "${w:-0}" -gt 0 && "${h:-0}" -gt 0 && "${r:-0}" -gt 0 ]] && args=(-W "$w" -H "$h" -r "$r") +fi +if [[ "${1:-}" == --print-args ]]; then echo "${args[*]}"; exit 0; fi +exec "$real" "${args[@]}" "$@" diff --git a/patches/gamescope-nvidia.PKGBUILD b/patches/gamescope-nvidia.PKGBUILD index 6b6b7e5..cde2ea0 100644 --- a/patches/gamescope-nvidia.PKGBUILD +++ b/patches/gamescope-nvidia.PKGBUILD @@ -2,14 +2,14 @@ # Based on Arch Linux's gamescope PKGBUILD (Maxime Gauduin, Giancarlo Razzolini, Sven-Hendrik Haase and contributors). # # gamescope with GBM-allocated scan-out buffers for NVIDIA (opt-in: gamescope_drm_gbm_scanout=1). -# The patch is gamescope-gbm-scanout.patch (next to this file; see its header for where it comes from). pkgver is the gamescope -# release the patch was made for and tested with. Kept in sync with https://github.com/theupriser/steamify-gamescope-nvidia; -# Steamify (lib/gamescope-nvidia.sh) writes both files into a temporary folder and runs makepkg there. +# The patches are gamescope-gbm-scanout.patch and gamescope-ui-native.patch (next to this file, applied in this order); see the +# README for where they come from. +# UPSTREAM_VERSION (next to this file) names the gamescope tag the patch is made for. pkgname=steamify-gamescope-nvidia _srcname=gamescope pkgver=3.16.31 -pkgrel=1 +pkgrel=2 pkgdesc='SteamOS session compositing window manager, with GBM scan-out for NVIDIA (opt-in: gamescope_drm_gbm_scanout=1)' arch=(x86_64) url=https://github.com/theupriser/steamify-gamescope-nvidia @@ -73,6 +73,7 @@ makedepends=( source=( gamescope::git+https://github.com/ValveSoftware/gamescope.git#commit=${pkgver} gamescope-gbm-scanout.patch + gamescope-ui-native.patch git+https://gitlab.freedesktop.org/emersion/libdisplay-info.git git+https://gitlab.freedesktop.org/emersion/libliftoff.git git+https://github.com/ValveSoftware/openvr.git @@ -89,6 +90,7 @@ b2sums=('SKIP' 'SKIP' 'SKIP' 'SKIP' + 'SKIP' 'SKIP') prepare() { @@ -98,6 +100,8 @@ prepare() { # silently produce an unpatched gamescope under this package's name. git apply --check ../gamescope-gbm-scanout.patch || { echo "gbm patch does not apply to gamescope ${pkgver}" >&2; return 1; } git apply ../gamescope-gbm-scanout.patch + git apply --check ../gamescope-ui-native.patch || { echo "ui-native patch does not apply to gamescope ${pkgver}" >&2; return 1; } + git apply ../gamescope-ui-native.patch meson subprojects download diff --git a/patches/gamescope-ui-native.patch b/patches/gamescope-ui-native.patch new file mode 100644 index 0000000..78473fc --- /dev/null +++ b/patches/gamescope-ui-native.patch @@ -0,0 +1,39 @@ +Keeps Steam's UI X server (server 0) at the output size when Steam asks for a smaller one. + +With -steamos3 (what gamescope-session-cachyos passes) Steam sets its UI to 1920x1080 right after it starts +(GAMESCOPE_XWAYLAND_MODE_CONTROL), so on a bigger display, and on one that isn't 16:9, the whole interface is a scaled-up +1080p picture. Games already run at the display's size. With this the server stays at the output size and Steam draws its +window to match; Steam's SteamOS features (settings pages, game launching) keep working. Written for Steamify on an NVIDIA +PC (RTX 5080, 3440x1440@175, tested with Steam's UI and a Proton game); not part of the farnoy patch. On by default; the +setting gamescope_xwayland_ui_native=0 (in gamescope's environment) turns it off. +Applies with `git apply` after gamescope-gbm-scanout.patch (it ignores these lines). + +diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp +index 2cb5eb5..ce14c8d 100644 +--- a/src/steamcompmgr.cpp ++++ b/src/steamcompmgr.cpp +@@ -129,6 +129,8 @@ LogScope g_WaitableLog("waitable"); + + gamescope::ConVar cv_overlay_unmultiplied_alpha{ "overlay_unmultiplied_alpha", false }; + ++gamescope::ConVar cv_xwayland_ui_native( "xwayland_ui_native", true, "Keep the Steam UI X server (server 0) at the output size when Steam asks for a smaller one." ); ++ + gamescope::ConVar cv_vr_show_forwarded_overlays{ "vr_show_forwarded_overlays", false }; + + std::string *g_pVROverlayKey = nullptr; +@@ -7240,6 +7242,15 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) + height = std::min(height, currentOutputHeight); + } + ++ // Steam asks for a smaller size for its own UI (server 0, 1920x1080 with -steamos3), which makes the whole ++ // interface a scaled-up picture on a bigger display, and on one that isn't 16:9 as well. The UI server ++ // stays at the output size: Steam sizes its window to the server. ++ if ( server_idx == 0 && cv_xwayland_ui_native ) ++ { ++ width = currentOutputWidth; ++ height = currentOutputHeight; ++ } ++ + gamescope_xwayland_server_t *server = wlserver_get_xwayland_server( server_idx ); + if ( server ) + { From 50dbf3355e1bffa3ff94a017c2b4b59d3ad62e16 Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 20:10:33 +0200 Subject: [PATCH 21/26] Patched gamescope: one build per CPU level (znver4/v4/v3/generic), smoke test after install, pin 3.16.31-3 --- lib/gamescope-nvidia.sh | 79 +++++++++++++++++++++---------- patches/gamescope-nvidia.PKGBUILD | 4 +- 2 files changed, 57 insertions(+), 26 deletions(-) diff --git a/lib/gamescope-nvidia.sh b/lib/gamescope-nvidia.sh index 4d2b0ad..7b525d6 100644 --- a/lib/gamescope-nvidia.sh +++ b/lib/gamescope-nvidia.sh @@ -20,8 +20,14 @@ GSN_PKG=steamify-gamescope-nvidia GSN_RELEASES="${GSN_RELEASES:-https://github.com/theupriser/steamify-gamescope-nvidia/releases}" # The package this Steamify release was tested with (patches/gamescope-nvidia.PKGBUILD names the same version): the # fallback. A new pin: the release's tag, the package's sha256, and the PKGBUILD's pkgver/pkgrel. -GSN_VERSION=3.16.31-2 -GSN_SHA256=3b981bed4dfdac383d22b8c22feaef191c2f2863bccf5676d1ec959c2c5ee3a3 +GSN_VERSION=3.16.31-3 +# One build per CPU level, like CachyOS's repositories: generic is the one every x86-64 PC can run. +declare -A GSN_SHA256=( + [generic]=4c7995694d2726c356785d9aec12a11c98419b4d2e139617f03bb46c758ced56 + [v3]=43c6928ca9fa67c063c4e1b993b686145e94e68de1bd46645782d3186779fa2d + [v4]=b6d4621e4b98d9aa5c600fe9a5a1cae164fef6bbf93d259fb8a6af666b098f9f + [znver4]=60f45da74a0b96d776219f6e6aa22c5d23e48b08233b3fa12b6c4d7aa6812dd9 +) # Where the ISO leaves a copy of the pinned package, for installs without GitHub. GSN_BACKUP_DIR="${GSN_BACKUP_DIR:-/usr/local/share/steamify/gamescope}" # How long a look at GitHub for a newer release counts (seconds), so opening the menu doesn't ask every time. @@ -68,20 +74,30 @@ gsn_update_pending() { [[ -n "$latest" ]] && gsn_newer "$latest" "$(gsn_installed_version)" } +gsn_cpu_variant() { + # The best build this CPU can run: znver4 (Ryzen 7000/9000: AMD with AVX-512 BF16), v4, v3, else generic. The + # dynamic loader knows the CPU level best ("x86-64-v4 (supported, searched)"). + local help; help="$(/lib64/ld-linux-x86-64.so.2 --help 2>/dev/null)" + if grep -q 'x86-64-v4 (supported' <<< "$help"; then + if grep -q AuthenticAMD /proc/cpuinfo && grep -qw avx512_bf16 /proc/cpuinfo; then echo znver4; else echo v4; fi + elif grep -q 'x86-64-v3 (supported' <<< "$help"; then echo v3 + else echo generic; fi +} + gsn_sha_of() { # The hash a release file is expected to have: the pinned one for the pinned version, else the .sha256 next to the - # package in the same release (it shows the download wasn't damaged, not who made it). - local tag="$1" file="$2" - if [[ "$tag" == "$GSN_VERSION" ]]; then echo "$GSN_SHA256"; return 0; fi + # package in the same release (it shows the download wasn't damaged, not who made it). gsn_sha_of + local tag="$1" file="$2" variant="$3" + if [[ "$tag" == "$GSN_VERSION" ]]; then echo "${GSN_SHA256[$variant]}"; return 0; fi curl -fsL --connect-timeout 10 --max-time 30 "$GSN_RELEASES/download/$tag/$file.sha256" 2>/dev/null | awk 'NR==1 {print $1}' } gsn_download() { - # gsn_download : the release's package, verified, in the cache; prints its path. - local tag="$1" cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify" file want got - file="$GSN_PKG-$tag-x86_64.pkg.tar.zst" + # gsn_download : the release's package, verified, in the cache; prints its path. + local tag="$1" variant="$2" cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify" file want got + file="$GSN_PKG-$tag-$variant.pkg.tar.zst" mkdir -p "$cache" || return 1 - want="$(gsn_sha_of "$tag" "$file")" + want="$(gsn_sha_of "$tag" "$file" "$variant")" [[ "$want" =~ ^[0-9a-f]{64}$ ]] || return 1 if [[ -f "$cache/$file" ]] && [[ "$(sha256sum "$cache/$file" | awk '{print $1}')" == "$want" ]]; then echo "$cache/$file"; return 0; fi curl -fsL --retry 2 --connect-timeout 15 --max-time 300 -o "$cache/$file.part" "$GSN_RELEASES/download/$tag/$file" || { rm -f "$cache/$file.part"; return 1; } @@ -92,27 +108,37 @@ gsn_download() { } gsn_fetch_package() { - # The package to install, as a path, newest first: the newest release on GitHub (not older than the pinned one), else - # the pinned package (GitHub, the cache, or the copy that came with the ISO). Only files with the expected sha256 count. - local tag pkg cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify" file="$GSN_PKG-$GSN_VERSION-x86_64.pkg.tar.zst" copy + # The package to install, as a path: the build for this CPU, then the generic one, each from the newest release on + # GitHub (not older than the pinned one), else the pinned release (GitHub, the cache, or the copy that came with the + # ISO). Only files with the expected sha256 count. gsn_fetch_package [variant] + local tag pkg v cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify" file copy + local -a variants=("${1:-$(gsn_cpu_variant)}"); [[ "${variants[0]}" == generic ]] || variants+=(generic) tag="$(gsn_latest_tag)" || tag="" - if [[ -n "$tag" && "$tag" != "$GSN_VERSION" ]] && gsn_newer "$tag" "$GSN_VERSION"; then - info "Downloading the newest patched gamescope ($tag)..." >&2 - if pkg="$(gsn_download "$tag")"; then echo "$pkg"; return 0; fi - warn "Downloading the newest patched gamescope ($tag) failed: using the version this Steamify was tested with ($GSN_VERSION)." >&2 - fi - info "Downloading the patched gamescope ($GSN_VERSION)..." >&2 - if pkg="$(gsn_download "$GSN_VERSION")"; then echo "$pkg"; return 0; fi - warn "Downloading the patched gamescope failed (or its checksum didn't match)." >&2 - for copy in "$GSN_BACKUP_DIR/$file" "$cache/$file"; do - if [[ -f "$copy" ]] && [[ "$(sha256sum "$copy" | awk '{print $1}')" == "$GSN_SHA256" ]]; then - info "Using the copy that came with Steamify: $copy" >&2 - echo "$copy"; return 0 + for v in "${variants[@]}"; do + if [[ -n "$tag" && "$tag" != "$GSN_VERSION" ]] && gsn_newer "$tag" "$GSN_VERSION"; then + info "Downloading the newest patched gamescope ($tag, $v)..." >&2 + if pkg="$(gsn_download "$tag" "$v")"; then echo "$pkg"; return 0; fi + warn "Downloading the newest patched gamescope ($tag, $v) failed: trying the version this Steamify was tested with ($GSN_VERSION)." >&2 fi + info "Downloading the patched gamescope ($GSN_VERSION, $v)..." >&2 + if pkg="$(gsn_download "$GSN_VERSION" "$v")"; then echo "$pkg"; return 0; fi + file="$GSN_PKG-$GSN_VERSION-$v.pkg.tar.zst" + for copy in "$GSN_BACKUP_DIR/$file" "$cache/$file"; do + if [[ -f "$copy" ]] && [[ "$(sha256sum "$copy" | awk '{print $1}')" == "${GSN_SHA256[$v]}" ]]; then + info "Using the copy that came with Steamify: $copy" >&2 + echo "$copy"; return 0 + fi + done done + warn "Downloading the patched gamescope failed (or its checksum didn't match)." >&2 return 1 } +gsn_smoke_test() { + # The installed gamescope must start (headless, no screen needed): a build that crashes would leave gaming mode in a loop. + timeout 25 gamescope --backend headless -W 640 -H 360 -r 60 -- true >/dev/null 2>&1 +} + gsn_build_package() { # Last resort: builds the pinned package from the recipe and patch Steamify carries (patches/), as the user. It # downloads gamescope's sources (Valve's repository at the PKGBUILD's pkgver, and its submodules) and compiles them: a @@ -154,6 +180,11 @@ gsn_install_package() { if [[ -z "$latest" ]] && ! gsn_newer "$GSN_VERSION" "$have"; then return 0; fi fi if pkg="$(gsn_fetch_package)" && sudo pacman -U --noconfirm --ask 4 "$pkg"; then + if ! gsn_smoke_test; then + warn "The patched gamescope for this CPU doesn't start: installing the generic build instead." + pkg="$(gsn_fetch_package generic)" && sudo pacman -U --noconfirm --ask 4 "$pkg" && gsn_smoke_test || + { err "The patched gamescope doesn't start on this PC."; return 1; } + fi ok "Patched gamescope installed." return 0 fi diff --git a/patches/gamescope-nvidia.PKGBUILD b/patches/gamescope-nvidia.PKGBUILD index cde2ea0..2009b63 100644 --- a/patches/gamescope-nvidia.PKGBUILD +++ b/patches/gamescope-nvidia.PKGBUILD @@ -4,12 +4,12 @@ # gamescope with GBM-allocated scan-out buffers for NVIDIA (opt-in: gamescope_drm_gbm_scanout=1). # The patches are gamescope-gbm-scanout.patch and gamescope-ui-native.patch (next to this file, applied in this order); see the # README for where they come from. -# UPSTREAM_VERSION (next to this file) names the gamescope tag the patch is made for. +# UPSTREAM_VERSION (next to this file) names the gamescope tag the patches are made for. pkgname=steamify-gamescope-nvidia _srcname=gamescope pkgver=3.16.31 -pkgrel=2 +pkgrel=3 pkgdesc='SteamOS session compositing window manager, with GBM scan-out for NVIDIA (opt-in: gamescope_drm_gbm_scanout=1)' arch=(x86_64) url=https://github.com/theupriser/steamify-gamescope-nvidia From 0b7558b3b5c89b29150a6e922d86e2e1efbbcfab Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 20:11:59 +0200 Subject: [PATCH 22/26] Smoke test: pass when gamescope ran the program (it segfaults on headless exit) --- lib/gamescope-nvidia.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/gamescope-nvidia.sh b/lib/gamescope-nvidia.sh index 7b525d6..4e6f5ea 100644 --- a/lib/gamescope-nvidia.sh +++ b/lib/gamescope-nvidia.sh @@ -136,7 +136,8 @@ gsn_fetch_package() { gsn_smoke_test() { # The installed gamescope must start (headless, no screen needed): a build that crashes would leave gaming mode in a loop. - timeout 25 gamescope --backend headless -W 640 -H 360 -r 60 -- true >/dev/null 2>&1 + # It segfaults while shutting down headless (also unpatched builds), so what counts is that it ran the program. + timeout 25 gamescope --backend headless -W 640 -H 360 -r 60 -- true 2>&1 | grep -q 'Primary child shut down' } gsn_build_package() { From 852a9d80d7545eef2481034fa3cef15220212123 Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 20:16:09 +0200 Subject: [PATCH 23/26] Docs: per-CPU-level gamescope builds --- AGENTS.md | 2 +- CHANGELOG.md | 3 ++- TECHNICAL.md | 4 ++-- patches/README.md | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index aff9ea2..7921e10 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -53,7 +53,7 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine newest release of theupriser/steamify-gamescope-nvidia, with the pinned package (`GSN_VERSION`, `GSN_SHA256`), the copy the ISO leaves, and a build here (`patches/gamescope-nvidia.PKGBUILD` + the two patches) as the fallback. "Gaming on NVIDIA" (`nvidia`, `bigpicture`, `nvsilent`) isn't offered any more (`nvidia_available`); turning the conversion on turns it off (`nvidia_swap_out`). - A new pin = the release's tag + its sha256 in `lib/gamescope-nvidia.sh` and the PKGBUILD's pkgver/pkgrel, copied from the + Builds exist per CPU level (`gsn_cpu_variant`: znver4, v4, v3, generic; `GSN_SHA256` is a map; the installed one must pass `gsn_smoke_test`, else generic). A new pin = the release's tag + each variant's sha256 (from `SHA256SUMS`) in `lib/gamescope-nvidia.sh` and the PKGBUILD's pkgver/pkgrel, copied from the repository (the patches in `patches/` must stay identical to that repository's). Steam must keep running with `-steamos3` (without it games don't launch in gaming mode and the settings pages go): never "fix" the UI size by dropping flags or by `XWAYLAND_COUNT`. Tested on an RTX 5080 only; keep the branch behind `.no-release-yet` until the whole flow ran on hardware. diff --git a/CHANGELOG.md b/CHANGELOG.md index 115e689..fdb6217 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,8 @@ one per merged pull request. ## 2.11.2 - 2026-10-13 -- **feat: on NVIDIA the gaming session runs on the display's own mode and Steam's interface at its size: a second gamescope patch (`gamescope-ui-native.patch`, release `3.16.31-2` of steamify-gamescope-nvidia, now the pin) keeps Steam's UI X server at the output size when Steam (with `-steamos3`) asks for 1920x1080, and a wrapper (`gamescope-display-wrapper.sh`, set up by the conversion with a drop-in of `gamescope-session.service`) starts gamescope on the mode KDE has saved for the connected display, else the biggest mode at the highest refresh rate: before, gaming mode ran at the display's preferred mode (60 Hz on many monitors) with a 1080p Steam UI. Tested on an RTX 5080, 3440x1440@175: widescreen, sharp, a Proton game starts** +- **feat: the patched gamescope comes in one build per CPU level, like CachyOS's repositories (generic, x86-64-v3, v4, znver4): Steamify picks the best one this CPU can run (`gsn_cpu_variant`), falls back to generic, and starts the installed gamescope once headless (`gsn_smoke_test`): a build that doesn't start is replaced by the generic one. CI compiles each with an explicit `-march` (a `-march=native` build died with SIGILL on a Ryzen) and checks the binary for instructions beyond its level.** +- **feat: on NVIDIA the gaming session runs on the display's own mode and Steam's interface at its size: a second gamescope patch (`gamescope-ui-native.patch`, release `3.16.31-3` of steamify-gamescope-nvidia, now the pin; built once per CPU level, see below) keeps Steam's UI X server at the output size when Steam (with `-steamos3`) asks for 1920x1080, and a wrapper (`gamescope-display-wrapper.sh`, set up by the conversion with a drop-in of `gamescope-session.service`) starts gamescope on the mode KDE has saved for the connected display, else the biggest mode at the highest refresh rate: before, gaming mode ran at the display's preferred mode (60 Hz on many monitors) with a 1080p Steam UI. Tested on an RTX 5080, 3440x1440@175: widescreen, sharp, a Proton game starts** - **fix: on an NVIDIA PC that had single user mode on before the SteamOS conversion, "Return to Gaming Mode" and the boot choice work again: single user mode's desktop autologin (`zzz-steamify-autologin.conf`, read last) pinned the Plasma session; the conversion removes it, and turning the conversion off sets it up again** diff --git a/TECHNICAL.md b/TECHNICAL.md index a3572e6..fdd197f 100644 --- a/TECHNICAL.md +++ b/TECHNICAL.md @@ -244,8 +244,8 @@ without. The patch is nine commits of [farnoy/gamescope](https://github.com/farn `patches/` (`gamescope-gbm-scanout.patch` and the recipe `gamescope-nvidia.PKGBUILD`, kept in sync with [steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia), where new gamescope versions are prepared). gamescope changes every few weeks, so the package is downloaded, not carried: `gsn_install_package` takes the -**newest release** of that repository (CI builds it in CachyOS's container; a person merges the version bump), checked against the -`.sha256` of the same release, and installs it with `pacman -U --ask 4` (the package provides and conflicts with `gamescope`). What +**newest release** of that repository (CI builds it in CachyOS's container, once per CPU level: generic, v3, v4, znver4, each checked for instructions beyond its level; a person merges the version bump). `gsn_cpu_variant` picks the build for this CPU (the dynamic loader's x86-64 level; AMD with `avx512_bf16` is znver4), generic is the fallback, and `gsn_smoke_test` runs the installed gamescope headless and swaps in generic when it doesn't start. The package is checked against the pinned hash +or the release's `.sha256`, and installed with `pacman -U --ask 4` (the package provides and conflicts with `gamescope`). What this Steamify release was tested with is the fallback, in this order: the pinned package (`GSN_VERSION`, `GSN_SHA256`: from GitHub, the cache, or the copy the ISO leaves in `/usr/local/share/steamify/gamescope`), then a build here from the recipe and patch in `patches/` (`makepkg -sf` as the user, in `~/.cache/steamify`; no checksums on gamescope's own sources). A package that downloaded fine but diff --git a/patches/README.md b/patches/README.md index ae5b89c..5df96a2 100644 --- a/patches/README.md +++ b/patches/README.md @@ -17,7 +17,7 @@ read and reviewed on their own. `lib/*.sh` reads them with `patch_file | `steamify-nvidia-initramfs.sh`, `steamify-nvidia-initramfs.hook` | `lib/nvidia.sh` (SteamOS conversion, NVIDIA fix) | The pacman hook (before the initramfs is built, after DKMS) and its script: the NVIDIA modules go into the initramfs only while every installed kernel has them, decided again at every kernel or driver change (`fill SCRIPT=...`) | | `cros-ec-cec-single-port.patch` | `lib/cec.sh` (HDMI-CEC) | Makes Valve's Steam Machine CEC driver find amdgpu's HDMI port | | `gamescope-gbm-scanout.patch` | `lib/gamescope-nvidia.sh` (gamescope on NVIDIA) | gamescope 3.16.31 patch: scan-out buffers allocated with GBM (opt-in, `gamescope_drm_gbm_scanout=1`), which cures the corrupted picture on NVIDIA; from farnoy/gamescope, see the header of the file | -| `gamescope-nvidia.PKGBUILD` | `lib/gamescope-nvidia.sh` (gamescope on NVIDIA) | The recipe for the patched gamescope package (`steamify-gamescope-nvidia`, provides and conflicts with `gamescope`): Valve's gamescope at `pkgver` plus `gamescope-gbm-scanout.patch`; written with the patch to a temporary folder and built with `makepkg` | +| `gamescope-nvidia.PKGBUILD` | `lib/gamescope-nvidia.sh` (gamescope on NVIDIA) | The recipe for the patched gamescope package (CI builds it per CPU level; here it is only the local-build fallback) (`steamify-gamescope-nvidia`, provides and conflicts with `gamescope`): Valve's gamescope at `pkgver` plus `gamescope-gbm-scanout.patch`; written with the patch to a temporary folder and built with `makepkg` | | `cros-ec-cec.c` | `lib/cec.sh` (HDMI-CEC) | Valve's Steam Machine CEC driver (GPL-2.0+, from evlaV/linux-integration at the pinned commit): the backup when downloading it from GitHub fails; used only if its sha256 equals `CEC_DRIVER_SHA256` (a new pin needs a new copy) | | `python-hid-shim.PKGBUILD` | `lib/packages.sh` (required packages) | An empty package that provides `python-hid`, for PCs that keep `python-hidapi` (they conflict; jupiter-hw-support, a dependency of gamescope-session-cachyos, wants python-hid, only the Steam Deck controller updater uses it): built with `makepkg` and installed before the conversion's packages | | `gamescope-ui-native.patch` | `lib/gamescope-nvidia.sh` (gamescope on NVIDIA) | Small patch after the GBM one: keeps Steam's UI X server at the display's size when Steam (with `-steamos3`) asks for 1920x1080; `gamescope_xwayland_ui_native=0` turns it off | From 3e4c92cdbca7b47794404afd32083025bf079998 Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 20:16:43 +0200 Subject: [PATCH 24/26] NVIDIA setup: preflight (pacman lock, free space), failure marker with notification, reminder in the menu --- lib/gamescope-nvidia.sh | 31 ++++++++++++++++++++++++++++++- lib/menu.sh | 1 + 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/lib/gamescope-nvidia.sh b/lib/gamescope-nvidia.sh index 4e6f5ea..494af09 100644 --- a/lib/gamescope-nvidia.sh +++ b/lib/gamescope-nvidia.sh @@ -249,9 +249,37 @@ gsn_display_disable() { return 0 } +gsn_preflight() { + # Before anything changes: what would make the install fail half way. Prints the reason and fails, or passes. + if [[ -e /var/lib/pacman/db.lck ]]; then + echo "another package manager is running (/var/lib/pacman/db.lck): finish or close it and try again"; return 1 + fi + local free; free="$(df --output=avail -BM / 2>/dev/null | tail -1 | tr -dc 0-9)" + if [[ -n "$free" ]] && (( free < 1500 )); then + echo "less than 1.5 GB free on /: free some space and try again"; return 1 + fi + return 0 +} + +gsn_fail_mark() { + # Remember a failed setup so the menu says so on the next start, and tell the user now (desktop notification). + state_set gamescope_nvidia failed "$(date '+%Y-%m-%d %H:%M'): $1" + command -v notify-send >/dev/null 2>&1 && + notify-send -a Steamify -i dialog-warning "Steamify: gaming mode setup failed" "$1. Open Steamify and apply again." 2>/dev/null || true +} + +gsn_fail_note() { + # The menu's reminder of a failed setup (nothing when the last one worked). + local f; f="$(state_get gamescope_nvidia failed)" + [[ -n "$f" ]] && warn "The last gaming mode setup for NVIDIA failed ($f). Apply the conversion again to retry." + return 0 +} + gsn_enable() { # Only on a supported NVIDIA card; elsewhere the stock gamescope is right. nvidia_present || return 0 + local why + if ! why="$(gsn_preflight)"; then err "Gaming mode for NVIDIA can't be set up: $why."; gsn_fail_mark "$why"; return 1; fi # A PC that had "Gaming on NVIDIA" on: Steam must not also start on the desktop. nvidia_swap_out # What NVIDIA's DRM stack wants (lib/nvidia.sh; a supported card only, the functions check): modeset/fbdev on the @@ -259,7 +287,8 @@ gsn_enable() { # effect at the next boot, like the session. nvidia_kernel_enable || return 1 nvidia_extras_enable || return 1 - gsn_install_package || return 1 + gsn_install_package || { gsn_fail_mark "the patched gamescope couldn't be installed"; return 1; } + state_set gamescope_nvidia failed "" gsn_env_enable gsn_display_enable || warn "Couldn't set up the display mode for gaming mode: gamescope takes the display's preferred mode." ok "gamescope draws NVIDIA's picture through GBM (gamescope_drm_gbm_scanout=1) from the next gaming mode start." diff --git a/lib/menu.sh b/lib/menu.sh index a58d110..4bbd791 100644 --- a/lib/menu.sh +++ b/lib/menu.sh @@ -337,6 +337,7 @@ toggle_component() { show_menu() { local i=0 c now want echo + gsn_fail_note printf " ${c_bold}%-3s %-6s %-6s %s${c_reset}\n" "#" "Now" "Want" "Component" MENU_ITEMS=() for c in "${COMPONENTS[@]}"; do From ab3cfebe7c9cb8c2891396e4eee1a0a2cc79029a Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 20:23:04 +0200 Subject: [PATCH 25/26] gamescope-nvidia: glob instead of ls | grep (shellcheck SC2010) --- lib/gamescope-nvidia.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/gamescope-nvidia.sh b/lib/gamescope-nvidia.sh index 494af09..e6e6026 100644 --- a/lib/gamescope-nvidia.sh +++ b/lib/gamescope-nvidia.sh @@ -160,8 +160,11 @@ gsn_build_package() { rm -rf "$dir"; return 1 fi # Moved out, so the build folder can go. - mv "$(ls "$dir"/"$GSN_PKG"-*.pkg.tar.* 2>/dev/null | grep -v -- '-debug-' | head -1)" "$cache/gamescope-local-build.pkg.tar.zst" || - { rm -rf "$dir"; return 1; } + local f built="" + for f in "$dir"/"$GSN_PKG"-*.pkg.tar.*; do + [[ -e "$f" && "$f" != *-debug-* ]] && { built="$f"; break; } + done + [[ -n "$built" ]] && mv "$built" "$cache/gamescope-local-build.pkg.tar.zst" || { rm -rf "$dir"; return 1; } rm -rf "$dir" echo "$cache/gamescope-local-build.pkg.tar.zst" } From a7f8493d64d8d96d93ed9750eb58961c13b72d52 Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 13 Oct 2026 20:24:32 +0200 Subject: [PATCH 26/26] Version 2.12.0; drop the NVIDIA screenshot (NVIDIA PCs get the same menu) --- AGENTS.md | 7 +++---- CHANGELOG.md | 2 +- README.md | 11 +++-------- TECHNICAL.md | 4 ++-- assets/screenshot-menu-nvidia.png | Bin 282665 -> 0 bytes lib/menu.sh | 2 +- lib/nvidia.sh | 4 ++-- steamify.sh | 2 +- 8 files changed, 13 insertions(+), 19 deletions(-) delete mode 100644 assets/screenshot-menu-nvidia.png diff --git a/AGENTS.md b/AGENTS.md index 7921e10..69ce721 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -48,7 +48,7 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine `_available` is checked via `component_available` (e.g. `machine` only on Fremont). Turn-on order is `COMPONENTS` order, turn-off reverse; `gaming` must stay first. Dependencies live in `toggle_component`. -- **NVIDIA** (`lib/gamescope-nvidia.sh`, `lib/nvidia.sh`): since 2.11.2 the SteamOS conversion (`gaming` and its options) runs on +- **NVIDIA** (`lib/gamescope-nvidia.sh`, `lib/nvidia.sh`): since 2.12.0 the SteamOS conversion (`gaming` and its options) runs on NVIDIA PCs with a patched gamescope (GBM scan-out: gamescope#2309; Steam's UI kept at the display's size), downloaded as the newest release of theupriser/steamify-gamescope-nvidia, with the pinned package (`GSN_VERSION`, `GSN_SHA256`), the copy the ISO leaves, and a build here (`patches/gamescope-nvidia.PKGBUILD` + the two patches) as the fallback. "Gaming on NVIDIA" (`nvidia`, @@ -160,9 +160,8 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine a warning when `VERSION` is a version that's already released (so a release branch that forgot its bump shows it on every PR). - A release that adds, removes or renames a menu row also retakes the - README screenshots (`assets/screenshot-menu-steam-machine.png` and - `assets/screenshot-menu-nvidia.png`, side by side in the README): the app from the branch on a Steam Machine and on a PC - with an NVIDIA card, every row visible and each window only as tall as its options need, the header showing the new + README screenshot (`assets/screenshot-menu-steam-machine.png`; NVIDIA PCs get the same menu, so there is no separate + one): the app from the branch on a Steam Machine, every row visible and the window only as tall as its options need, the header showing the new `VERSION`, 1600 px wide. Size the window with a KWin script (match the `steamify-ui` class exactly: a title match also hits Konsole and editor windows) and crop the full-screen capture to the client rectangle; mind the display scale (the Steam Machine runs at 1.75). diff --git a/CHANGELOG.md b/CHANGELOG.md index fdb6217..7d27de6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes, per version and per commit. Versions follow `steamify.sh`. Versions before 0.7.0 were numbered afterwards, one per merged pull request. -## 2.11.2 - 2026-10-13 +## 2.12.0 - 2026-10-13 - **feat: the patched gamescope comes in one build per CPU level, like CachyOS's repositories (generic, x86-64-v3, v4, znver4): Steamify picks the best one this CPU can run (`gsn_cpu_variant`), falls back to generic, and starts the installed gamescope once headless (`gsn_smoke_test`): a build that doesn't start is replaced by the generic one. CI compiles each with an explicit `-march` (a `-march=native` build died with SIGILL on a Ryzen) and checks the binary for instructions beyond its level.** - **feat: on NVIDIA the gaming session runs on the display's own mode and Steam's interface at its size: a second gamescope patch (`gamescope-ui-native.patch`, release `3.16.31-3` of steamify-gamescope-nvidia, now the pin; built once per CPU level, see below) keeps Steam's UI X server at the output size when Steam (with `-steamos3`) asks for 1920x1080, and a wrapper (`gamescope-display-wrapper.sh`, set up by the conversion with a drop-in of `gamescope-session.service`) starts gamescope on the mode KDE has saved for the connected display, else the biggest mode at the highest refresh rate: before, gaming mode ran at the display's preferred mode (60 Hz on many monitors) with a 1080p Steam UI. Tested on an RTX 5080, 3440x1440@175: widescreen, sharp, a Proton game starts** diff --git a/README.md b/README.md index 01498b3..59b9a71 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,9 @@ # Steamify CachyOS -The Steamify app's menu. On a Steam Machine (or any PC with an AMD or Intel -graphics card) it offers the full SteamOS conversion, on the left. On a PC with -an NVIDIA graphics card gamescope's gaming mode shows a corrupted picture, so the -menu offers **Gaming on NVIDIA** instead (Steam on the desktop, started at login, -optionally in Big Picture), on the right. +The Steamify app's menu, on a Steam Machine. On a PC with an NVIDIA graphics card (GTX 16 / RTX 20 series or +newer) the same SteamOS conversion is offered; Steamify installs a patched gamescope for it. -| On a Steam Machine | On a PC with an NVIDIA graphics card | -|---|---| -| ![The Steamify app's menu on a Steam Machine](assets/screenshot-menu-steam-machine.png) | ![The Steamify app's menu on a PC with an NVIDIA graphics card](assets/screenshot-menu-nvidia.png) | +![The Steamify app's menu on a Steam Machine](assets/screenshot-menu-steam-machine.png) Turn a CachyOS desktop PC into a SteamOS-style console: it boots straight into Steam's Big Picture (gamescope), and you can switch to the KDE Plasma diff --git a/TECHNICAL.md b/TECHNICAL.md index fdd197f..2678fd9 100644 --- a/TECHNICAL.md +++ b/TECHNICAL.md @@ -238,7 +238,7 @@ no fix known). The kernel parameters `nvidia-drm.modeset=1`/`fbdev=1` and loadin window straight to the display. What does work on an RTX 5080: Steam's Big Picture (`steam -gamepadui`) as a normal window of the Plasma desktop session, smooth and clean. -Since 2.11.2 there is a second way: gamescope with GBM-allocated scan-out buffers (`lib/gamescope-nvidia.sh`). On an RTX 5080 +Since 2.12.0 there is a second way: gamescope with GBM-allocated scan-out buffers (`lib/gamescope-nvidia.sh`). On an RTX 5080 (driver 615.78.08, 3440x1440@175) Steam's gaming UI in gamescope's DRM session is clean with it and shows artifacts everywhere without. The patch is nine commits of [farnoy/gamescope](https://github.com/farnoy/gamescope) (`nvidia-gbm-wayland`), carried in `patches/` (`gamescope-gbm-scanout.patch` and the recipe `gamescope-nvidia.PKGBUILD`, kept in sync with @@ -260,7 +260,7 @@ newer, Turing and later): the kernel parameters, the early modules, suspend memo offered any more (`nvidia_available`); a PC that had it on keeps it until the conversion is turned on, which turns it off (`nvidia_swap_out`). Turning the conversion off removes the setting and those settings, and keeps the packages. Tested on an RTX 5080 only. -Before 2.11.2, with an NVIDIA GPU the SteamOS conversion (`gaming`, and its options `boot`, `single`, `glyphs`) wasn't offered, unless +Before 2.12.0, with an NVIDIA GPU the SteamOS conversion (`gaming`, and its options `boot`, `single`, `glyphs`) wasn't offered, unless it was already on. `nvidia` ("Gaming on NVIDIA", `lib/nvidia.sh`) took its place (both would start Steam at login): it installs `steam` when missing (recorded in state `nvidia`, removed again only then) and enables the user unit `steamify-steam-autostart.service` (`services/`, `ExecStart=/usr/bin/steam @ARGS@`, Plasma only). Its sub-option `bigpicture` ("Steam starts in Big Picture", ticked along with it) rewrites the unit with `-gamepadui` and sets diff --git a/assets/screenshot-menu-nvidia.png b/assets/screenshot-menu-nvidia.png deleted file mode 100644 index 5c936fca983ba21a43711a39d65b170cd6dc21c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 282665 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

~j;WDbq5yB!1$G5GiSQL4RaRZ_qNHRJvl|{&Vw3 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/dev/null } diff --git a/steamify.sh b/steamify.sh index cf39a0d..424923d 100755 --- a/steamify.sh +++ b/steamify.sh @@ -15,7 +15,7 @@ set -uo pipefail # Release version, see CHANGELOG.md. -VERSION=2.11.2 +VERSION=2.12.0 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"