diff --git a/ptlinux/gamebox_runtime.py b/ptlinux/gamebox_runtime.py index f78502b..3d77a1b 100644 --- a/ptlinux/gamebox_runtime.py +++ b/ptlinux/gamebox_runtime.py @@ -44,7 +44,6 @@ _X_PROPERTY_CHANGE_MASK = 1 << 22 _X_SUBSTRUCTURE_NOTIFY_MASK = 1 << 19 _X_SUBSTRUCTURE_REDIRECT_MASK = 1 << 20 _X_WM_STATE_WITHDRAWN = 0 -_X_WM_STATE_NORMAL = 1 _X_WM_STATE_ICONIC = 3 _NET_WM_STATE_REMOVE = 0 _NET_WM_STATE_SOURCE_APPLICATION = 1 @@ -450,18 +449,6 @@ class _X11: return None return values[0] - def restore_normal_window_state(self, window: int) -> bool: - """Undo a nested iconify request without raising the host window.""" - - self._replace_long_property( - window, - b"WM_STATE", - b"WM_STATE", - (_X_WM_STATE_NORMAL, 0), - ) - self.library.XSync(self.display, 0) - return self.window_state(window) == _X_WM_STATE_NORMAL - def window_is_borderless(self, window: int) -> bool | None: """Return whether the client currently requests no Motif decorations.""" @@ -1010,6 +997,13 @@ class _X11: return False return int(focused.value) == window + def window_is_active(self, window: int) -> bool: + """Return whether the desktop already considers this client active.""" + + root = self.library.XDefaultRootWindow(self.display) + active = self._long_property(root, b"_NET_ACTIVE_WINDOW", 1) + return bool(active and active[0] == window) + def activate_window(self, window: int) -> bool: """Ask the window manager to restore and activate one client.""" @@ -1436,15 +1430,19 @@ def _focus_game_window(mapper: _X11, window: int) -> None: def _repair_game_window_focus(mapper: _X11, window: int) -> bool: + """Repair Wine's input focus only while its desktop window remains active.""" + try: + if mapper.window_state(window) == _X_WM_STATE_ICONIC: + return False + if not mapper.window_is_active(window): + return False if mapper.window_is_focused(window): return True except Exception: return False try: - mapper.activate_window(window) - time.sleep(WINDOW_ACTIVATION_DELAY_SECONDS) - mapper.focus_window(window) + mapper.restore_input_focus(window) return mapper.window_is_focused(window) except Exception as exc: print( @@ -1460,6 +1458,8 @@ def _repair_gamescope_game_window_focus(mapper: _X11, window: int) -> bool: """Restore nested focus without asking the desktop to activate Gamescope.""" try: + if mapper.window_state(window) == _X_WM_STATE_ICONIC: + return False if mapper.window_is_focused(window): return True except Exception: @@ -1491,18 +1491,9 @@ def _resolve_gamescope_game_window( except Exception: state = None if state == _X_WM_STATE_ICONIC: - try: - if not mapper.restore_normal_window_state(window): - return None - except Exception: - return None - print( - "Game login window requested minimization; kept it visible inside " - "Gamescope.", - file=sys.stderr, - flush=True, - ) - return window + # IconicState can be a real desktop minimize request. Monitoring must never + # turn that user-controlled state back into a visible window. + return None if state is not None and state != _X_WM_STATE_WITHDRAWN: return window @@ -1733,18 +1724,22 @@ def _guard_game_window_startup( became_iconic = state == _X_WM_STATE_ICONIC entered_screen_filling_mode = screen_filling is True login_style_reset = borderless_was_applied and borderless_now is False + if became_iconic: + print( + "Game startup window was minimized; leaving it minimized.", + file=sys.stderr, + flush=True, + ) + return False if ( - not became_iconic - and not entered_screen_filling_mode + not entered_screen_filling_mode and not login_style_reset ): time.sleep(WINDOW_STARTUP_POLL_SECONDS) continue recovery_count += 1 - if became_iconic: - reason = "was minimized" - elif entered_screen_filling_mode: + if entered_screen_filling_mode: reason = "entered fullscreen/maximized mode" else: reason = "changed its window layout" diff --git a/ptlinux/gamescope_runtime.py b/ptlinux/gamescope_runtime.py index 4bbff41..d5c95a2 100644 --- a/ptlinux/gamescope_runtime.py +++ b/ptlinux/gamescope_runtime.py @@ -291,13 +291,16 @@ def _tune_process_window( window = mapper.find_window_by_pid(process.pid) if window is not None: increments = resize_increments(width, height) + # Some X11 window managers keep the maximize decoration hidden until + # both the size constraints and allowed actions advertise resizing. + scaling_enabled = mapper.enable_window_scaling(window) increments_applied = mapper.set_resize_increments( window, (width, height), increments, ) compositing_preferred = mapper.prefer_composited_presentation(window) - if increments_applied and compositing_preferred: + if scaling_enabled and increments_applied and compositing_preferred: return increments time.sleep(WINDOW_DISCOVERY_POLL_SECONDS) return None diff --git a/ptlinux/native/gamescope-3.16.20-ubuntu26.04-amd64 b/ptlinux/native/gamescope-3.16.20-ubuntu26.04-amd64 new file mode 100755 index 0000000..79c5b42 Binary files /dev/null and b/ptlinux/native/gamescope-3.16.20-ubuntu26.04-amd64 differ diff --git a/ptlinux/native/gamescope-compat.README b/ptlinux/native/gamescope-compat.README new file mode 100644 index 0000000..3bbd876 --- /dev/null +++ b/ptlinux/native/gamescope-compat.README @@ -0,0 +1,54 @@ +Gamescope compatibility binary +================================ + +gamescope-3.16.20-ubuntu26.04-amd64 is an isolated compatibility build for +Ubuntu 26.04 amd64. The launcher uses it only when the installed system +Gamescope reports version 3.16.20 and the binary passes its embedded SHA-256 +check. It never replaces /usr/games/gamescope. + +Source package: + Ubuntu gamescope 3.16.20+ds-1 + gamescope_3.16.20+ds.orig.tar.xz + SHA-256 a27984fdab2bbfe353efc772de214ae88cccab07c4507747ed4b7f063b2faa0e + gamescope_3.16.20+ds-1.debian.tar.xz + SHA-256 ae6e9bac39b576e7d9c15912a713796049a29756f6858364ef49bd02197cb153 + +Build: + ubuntu:26.04 container + apt-get build-dep gamescope + DEB_BUILD_OPTIONS=nocheck dpkg-buildpackage --build=binary --no-sign -jauto + +The source changes are: + + gamescope-wayland-letterbox-backing.patch + Backports upstream commit 66450376038864700f9b4721343b4d15b29c4198 + ("Use a backing surface for letter-boxing"). It fixes direct Wayland + output when a unity-scaled game surface has a nonzero letterbox offset. + + gamescope-wayland-libdecor-input-scope.patch + Keeps libdecor titlebar and resize-border button events out of the nested + application while preserving complete button sequences that begin on the + game surface. This prevents a decoration operation from leaving the game + with a permanently held mouse button. It addresses the behavior tracked + at https://github.com/ValveSoftware/gamescope/issues/2299. + + gamescope-lazy-output-images.patch + Backports upstream commit e383171ff1c0f7b5b37f05f2bb67f7c5282b087f + ("rendervulkan: make the shared output images on first use"). Direct + Wayland frames no longer allocate six output-sized Vulkan images at every + intermediate host-window size. + + gamescope-wayland-live-resize.patch + Skips the remaining device-idle wait and transparent fallback-image rebuild + when direct Wayland presentation has no live output images. Full-composition + frames still allocate correctly sized images on demand. + + gamescope-keep-nested-windows-visible.patch + Honors PTLINUX_GAMESCOPE_KEEP_WINDOWS_VISIBLE by rejecting the game's + login-transition iconify request. The outer desktop window retains its + normal size and visibility while host minimize and focus remain untouched. + +Binary SHA-256: + 3fc81536c22dcce2c593c11507a612c13221f5b2ce2e5326f7c63706ca965639 + +Licensing and copyright notices are in gamescope-compat.copyright. diff --git a/ptlinux/native/gamescope-compat.copyright b/ptlinux/native/gamescope-compat.copyright new file mode 100644 index 0000000..40af574 --- /dev/null +++ b/ptlinux/native/gamescope-compat.copyright @@ -0,0 +1,343 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Source: https://github.com/ValveSoftware/gamescope +Upstream-Name: gamescope +Upstream-Contact: Pierre-Loup A. Griffais +Comment: Build depends on libopenvr-dev which is in contrib +Files-Excluded: +# These files were excluded in the patch 0005_add_reshade_696b14c.patch + src/reshade/.gitignore + src/reshade/.gitmodules + src/reshade/res/main_icon.ico + src/reshade/res/main_icon_small.png + src/reshade/res/shaders/imgui_ps.spv + src/reshade/res/shaders/imgui_ps_hdr.spv + src/reshade/res/shaders/imgui_vs.spv + src/reshade/tools/7za.exe + src/reshade/examples + src/reshade/setup/Pages/Resources +# reshade gitmodules + src/reshade/deps/imgui + src/reshade/deps/minhook + src/reshade/deps/stb + src/reshade/deps/gl3w + src/reshade/deps/utfcpp + src/reshade/deps/spirv + src/reshade/deps/vma + src/reshade/deps/vulkan + src/reshade/deps/fpng + src/reshade/deps/d3d12 + src/reshade/deps/openxr + + +Files: + * +Copyright: + 2013-2023, Valve Corporation + 2022, NVIDIA CORPORATION +License: BSD-2-Clause + +Files: thirdparty/sol/* +Copyright: 2013-2020, Rapptz, ThePhD and contributors +License: Expat + +Files: scripts/00-gamescope/common/inspect.lua +Copyright: 2022, Enrique García Cota +License: Expat + +Files: src/color_helpers.h +Copyright: 2021-2022 Collabora, Ltd +License: Expat + +Files: src/messagey.h +Copyright: 1997-2022, Sam Lantinga +License: Zlib + +Files: + protocol/color-management-v1.xml +Copyright: + 2019 Sebastian Wick + 2019 Erwin Burema + 2020 AMD + 2020-2024 Collabora, Ltd. + 2024 Xaver Hugl + 2022-2025 Red Hat, Inc. +License: Expat + +Files: + protocol/frog-color-management-v1.xml +Copyright: + 2023, Joshua Ashton for Valve Software + 2023, Xaver Hugl +License: Expat + +Files: + protocol/gamescope-action-binding.xml +Copyright: + 2024 Valve Corporation +License: Expat + +Files: + protocol/gamescope-control.xml + protocol/gamescope-private.xml +Copyright: + 2023 Valve Corporation +License: Expat + +Files: + protocol/gamescope-input-method.xml +Copyright: + 2008-2011 Kristian Høgsberg + 2010-2011 Intel Corporation + 2012-2013 Collabora, Ltd. + 2012, 2013 Intel Corporation + 2015, 2016 Jan Arne Petersen + 2017, 2018 Red Hat, Inc. + 2018 Purism SPC + 2021 Valve Corporation +License: Expat + +Files: + protocol/gamescope-pipewire.xml + protocol/gamescope-xwayland.xml +Copyright: + 2021 Valve Corporation +License: Expat + +Files: + protocol/gamescope-reshade.xml +Copyright: + 2024, Wayne Heaney +License: Expat + +Files: + protocol/gamescope-swapchain.xml +Copyright: + 2023, Joshua Ashton for Valve Software +License: Expat + +Files: + protocol/wlr-layer-shell-unstable-v1.xml +Copyright: + 2017, Drew DeVault +License: HPND-sell-variant or NTP~disclaimer + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + . + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + +Files: + protocol/xdg-toplevel-icon-v1.xml +Copyright: + 2023-2024, Matthias Klumpp + 2024, David Edmundson +License: Expat + +Files: + src/shaders/NVIDIAImageScaling/* +Copyright: + 2022 NVIDIA CORPORATION & AFFILIATES +License: Expat + +Files: + src/shaders/ffx_*.h +Copyright: + 2021 Advanced Micro Devices, Inc. +License: Expat + +Files: + src/gpuvis_trace_utils.h +Copyright: + Michael Sartain +License: public-domain-dual + This software is dual-licensed to the public domain and under the following + license: you are granted a perpetual, irrevocable license to copy, modify, + publish, and distribute this file as you see fit. + +Files: + src/modegen.cpp +Copyright: + 2005-2006 Luc Verhaegen +License: Expat + +Files: + src/shaders/heatmap.h +Copyright: + Microsoft Corporation +License: Expat + +Files: + src/steamcompmgr.cpp +Copyright: + 2003 Keith Packard + Matthew Hawn +License: HPND-sell-variant + Permission to use, copy, modify, distribute, and sell this software and its + documentation for any purpose is hereby granted without fee, provided that + the above copyright notice appear in all copies and that both that + copyright notice and this permission notice appear in supporting + documentation, and that the name of Keith Packard not be used in + advertising or publicity pertaining to distribution of the software without + specific, written prior permission. Keith Packard makes no + representations about the suitability of this software for any purpose. It + is provided "as is" without express or implied warranty. + . + KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + PERFORMANCE OF THIS SOFTWARE. + +Files: + debian/* +Copyright: + 2022-2024 Stephan Lachnit + 2023-2024 Safir Secerovic + 2025 Ilya Orlov , +License: BSD-2-Clause + +Files: + src/reshade/* +Copyright: + 2014-2024 Patrick Mours. All rights reserved. +License: BSD-3-Clause + +Files: + src/reshade/deps/d3d911on12/* +Copyright: + Microsoft Corporation. +License: Expat + +Files: + src/reshade/deps/vulkan_layer/vk_layer_dispatch_table.h +Copyright: + 2015-2023, Google Inc. + 2015-2023, LunarG, Inc. + 2015-2023, The Khronos Group Inc. + 2015-2023, Valve Corporation +License: Apache-2.0 + +Files: src/reshade/source/imgui_code_editor.cpp +Copyright: + 2017, BalazsJako + 2018, Patrick Mours +License: Expat + +License: BSD-2-Clause + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + . + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + . + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + . + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +License: Expat + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + . + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +License: BSD-3-Clause + Copyright (c) The Regents of the University of California. + All rights reserved. + . + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + . + THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + +License: Zlib + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + . + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + . + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + +License: Apache-2.0 + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + . + http://www.apache.org/licenses/LICENSE-2.0 + . + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + . + On Debian systems, the full text of the Apache Software License version 2 can + be found in the file `/usr/share/common-licenses/Apache-2.0'. diff --git a/ptlinux/native/gamescope-keep-nested-windows-visible.patch b/ptlinux/native/gamescope-keep-nested-windows-visible.patch new file mode 100644 index 0000000..fbd3a01 --- /dev/null +++ b/ptlinux/native/gamescope-keep-nested-windows-visible.patch @@ -0,0 +1,34 @@ +From: PT Linux Launcher maintainers +Subject: Keep the nested game window visible during its login transition + +PristonTale replaces its startup presentation while entering the login screen +and asks the nested X11 window manager to mark the game window iconic. Gamescope +3.16.20 acknowledges that request by publishing IconicState even though the +surface stays mapped. Wine then hides or resizes the client, which also changes +the outer Gamescope presentation. + +When the launcher opts in through PTLINUX_GAMESCOPE_KEEP_WINDOWS_VISIBLE, keep +the nested client in NormalState. This is scoped to the launcher environment; +Gamescope retains its upstream behavior for every other invocation. Desktop +minimize and focus operate on the outer Wayland window and remain unaffected. + +--- a/src/steamcompmgr.cpp ++++ b/src/steamcompmgr.cpp +@@ -5361,8 +5361,17 @@ static void + handle_wm_change_state(xwayland_ctx_t *ctx, steamcompmgr_win_t *w, XClientMessageEvent *ev) + { + long state = ev->data.l[0]; ++ static const bool bKeepNestedWindowsVisible = env_to_bool( ++ getenv( "PTLINUX_GAMESCOPE_KEEP_WINDOWS_VISIBLE" ) ); + + if (state == ICCCM_ICONIC_STATE) { ++ if ( bKeepNestedWindowsVisible ) ++ { ++ xwm_log.debugf("Ignoring WM_CHANGE_STATE to ICONIC for window 0x%lx", w->xwayland().id); ++ set_wm_state( ctx, w->xwayland().id, ICCCM_NORMAL_STATE ); ++ return; ++ } ++ + xwm_log.debugf("Faking WM_CHANGE_STATE to ICONIC for window 0x%lx", w->xwayland().id); + set_wm_state( ctx, w->xwayland().id, ICCCM_ICONIC_STATE ); + } else { diff --git a/ptlinux/native/gamescope-lazy-output-images.patch b/ptlinux/native/gamescope-lazy-output-images.patch new file mode 100644 index 0000000..1c140b0 --- /dev/null +++ b/ptlinux/native/gamescope-lazy-output-images.patch @@ -0,0 +1,80 @@ +From: Matthew Schwartz +Subject: Lazily allocate shared Vulkan output images +Origin: upstream, commit e383171ff1c0f7b5b37f05f2bb67f7c5282b087f + +Backport the upstream lazy-allocation change to Gamescope 3.16.20. Native +Wayland presentation normally sends the game's DMA-BUF directly to the host +compositor, so allocating six output-sized Vulkan images at startup and after +every host-window configure is unnecessary. Allocate those images only if a +frame actually needs full Vulkan composition. + +--- a/src/rendervulkan.cpp ++++ b/src/rendervulkan.cpp +@@ -3345,6 +3345,31 @@ static bool vulkan_make_output_images( VulkanOutput_t *pOutput ) + return true; + } + ++// Without a swapchain the shared images are ours to make, so they wait for their first use. ++static bool vulkan_defer_output_images() ++{ ++ return !GetBackend()->UsesVulkanSwapchain(); ++} ++ ++static bool vulkan_ensure_output_images() ++{ ++ if ( !vulkan_defer_output_images() ) ++ return true; ++ ++ VulkanOutput_t *pOutput = &g_output; ++ if ( !pOutput->outputImages.empty() && pOutput->outputImages[0] ) ++ return true; ++ ++ vk_log.debugf( "Making the shared output images on first use" ); ++ if ( vulkan_make_output_images( pOutput ) ) ++ return true; ++ ++ // A half-made set would pass the check above, so the next use tries again from nothing. ++ pOutput->outputImages.clear(); ++ pOutput->outputImagesPartialOverlay.clear(); ++ return false; ++} ++ + bool vulkan_remake_output_images() + { + VulkanOutput_t *pOutput = &g_output; +@@ -3355,6 +3380,14 @@ bool vulkan_remake_output_images() + for (auto& pScreenshotImage : pOutput->pScreenshotImages) + pScreenshotImage = nullptr; + ++ if ( vulkan_defer_output_images() ) ++ { ++ pOutput->outputImages.clear(); ++ pOutput->outputImagesPartialOverlay.clear(); ++ pOutput->temporaryHackyBlankImage = vulkan_create_debug_blank_texture(); ++ return true; ++ } ++ + bool bRet = vulkan_make_output_images( pOutput ); + assert( bRet ); + return bRet; +@@ -3433,7 +3466,9 @@ bool vulkan_make_output() + return false; + } + +- if ( !vulkan_make_output_images( pOutput ) ) ++ if ( vulkan_defer_output_images() ) ++ pOutput->temporaryHackyBlankImage = vulkan_create_debug_blank_texture(); ++ else if ( !vulkan_make_output_images( pOutput ) ) + return false; + } + +@@ -3980,6 +4015,9 @@ std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamesco + g_reshadeManager.clear(); + } + ++ if ( !pOutputOverride && !vulkan_ensure_output_images() ) ++ return std::nullopt; ++ + gamescope::Rc compositeImage; + if ( pOutputOverride ) + compositeImage = pOutputOverride; diff --git a/ptlinux/native/gamescope-wayland-letterbox-backing.patch b/ptlinux/native/gamescope-wayland-letterbox-backing.patch new file mode 100644 index 0000000..a4f1713 --- /dev/null +++ b/ptlinux/native/gamescope-wayland-letterbox-backing.patch @@ -0,0 +1,21 @@ +From: PT Linux Launcher maintainers +Subject: Use a backing surface for letter-boxing + +Backport upstream commit 66450376038864700f9b4721343b4d15b29c4198 so +native Wayland presentation covers the complete configured output when the +game layer is unity-scaled with a non-zero letterbox offset. + +--- a/src/Backends/WaylandBackend.cpp ++++ b/src/Backends/WaylandBackend.cpp +@@ -1081,7 +1081,10 @@ namespace gamescope + bool bNeedsBacking = true; + if ( pFrameInfo->layerCount >= 1 ) + { +- if ( pFrameInfo->layers[0].isScreenSize() && !pFrameInfo->layers[0].hasAlpha() ) ++ if ( pFrameInfo->layers[0].isScreenSize() && ++ close_enough( pFrameInfo->layers[0].offset.x, 0.0f ) && ++ close_enough( pFrameInfo->layers[0].offset.y, 0.0f ) && ++ !pFrameInfo->layers[0].hasAlpha() ) + bNeedsBacking = false; + } + diff --git a/ptlinux/native/gamescope-wayland-libdecor-input-scope.patch b/ptlinux/native/gamescope-wayland-libdecor-input-scope.patch new file mode 100644 index 0000000..eb46366 --- /dev/null +++ b/ptlinux/native/gamescope-wayland-libdecor-input-scope.patch @@ -0,0 +1,64 @@ +From: PT Linux Launcher maintainers +Subject: Keep client-side decoration clicks out of nested applications +Bug: https://github.com/ValveSoftware/gamescope/issues/2299 +Forwarded: https://github.com/ValveSoftware/gamescope/issues/2299 + +On compositors without xdg-decoration support, libdecor creates client-side +surfaces owned by the Gamescope Wayland connection. Pointer button callbacks +for those titlebar and resize surfaces consequently also reach Gamescope's +input thread. Forwarding a decoration press to the nested application can +leave its button permanently held because libdecor consumes the matching +release while performing a move, resize, or maximize operation. + +Only begin nested button sequences while the pointer is over Gamescope's +actual toplevel surface. Track those presses so their releases are delivered +even if the pointer or keyboard focus changes during a game-originated drag. + +--- a/src/Backends/WaylandBackend.cpp ++++ b/src/Backends/WaylandBackend.cpp +@@ -562,6 +562,7 @@ + + std::atomic> m_pRelativePointer = nullptr; + std::unordered_set m_uScancodesHeld; ++ std::unordered_set m_uMouseButtonsHeld; + + void Wayland_Registry_Global( wl_registry *pRegistry, uint32_t uName, const char *pInterface, uint32_t uVersion ); + static const wl_registry_listener s_RegistryListener; +@@ -3091,13 +3092,33 @@ + } + void CWaylandInputThread::Wayland_Pointer_Button( wl_pointer *pPointer, uint32_t uSerial, uint32_t uTime, uint32_t uButton, uint32_t uState ) + { +- // Don't do any motion/movement stuff if we don't have kb focus +- if ( !cv_wayland_mouse_warp_without_keyboard_focus && !m_bKeyboardEntered ) +- return; ++ const bool bPressed = uState == WL_POINTER_BUTTON_STATE_PRESSED; ++ const bool bWasPressed = m_uMouseButtonsHeld.contains( uButton ); ++ ++ if ( bPressed ) ++ { ++ // libdecor's client-side decorations share our Wayland seat, but ++ // their button events must not be sent to the nested application. ++ if ( !m_bMouseEntered || bWasPressed ) ++ return; ++ ++ // Don't start an application click without keyboard focus. ++ if ( !cv_wayland_mouse_warp_without_keyboard_focus && !m_bKeyboardEntered ) ++ return; ++ } ++ else if ( !bWasPressed ) ++ { ++ return; ++ } + + wlserver_lock(); +- wlserver_mousebutton( uButton, uState == WL_POINTER_BUTTON_STATE_PRESSED, ++m_uFakeTimestamp ); ++ wlserver_mousebutton( uButton, bPressed, ++m_uFakeTimestamp ); + wlserver_unlock(); ++ ++ if ( bPressed ) ++ m_uMouseButtonsHeld.emplace( uButton ); ++ else ++ m_uMouseButtonsHeld.erase( uButton ); + } + void CWaylandInputThread::Wayland_Pointer_Axis( wl_pointer *pPointer, uint32_t uTime, uint32_t uAxis, wl_fixed_t fValue ) + { diff --git a/ptlinux/native/gamescope-wayland-live-resize.patch b/ptlinux/native/gamescope-wayland-live-resize.patch new file mode 100644 index 0000000..7ebdcfd --- /dev/null +++ b/ptlinux/native/gamescope-wayland-live-resize.patch @@ -0,0 +1,50 @@ +From: PT Linux Launcher maintainers +Subject: Avoid idle waits for direct Wayland resize configures + +The lazy-output-images backport leaves no shared output images allocated while +Gamescope is presenting the game directly as Wayland planes. A host-window +configure nevertheless calls vulkan_remake_output_images(), whose unconditional +device-idle wait and output-sized blank-texture recreation stall the compositor +thread for every intermediate drag size. + +Wait only when an output or screenshot image actually exists. The transparent +fallback texture is unused by the non-session Wayland backend, so retain it +across Wayland size changes; session backends preserve the existing recreation +behavior. If a frame later requires full composition, the lazy allocation path +creates correctly sized output images before rendering it. + +--- a/src/rendervulkan.cpp ++++ b/src/rendervulkan.cpp +@@ -3374,7 +3374,21 @@ static bool vulkan_ensure_output_images() + bool vulkan_remake_output_images() + { + VulkanOutput_t *pOutput = &g_output; +- g_device.waitIdle(); ++ bool bHasLiveImages = ++ !pOutput->outputImages.empty() && pOutput->outputImages[0]; ++ if ( !bHasLiveImages ) ++ { ++ for ( const auto &pScreenshotImage : pOutput->pScreenshotImages ) ++ { ++ if ( pScreenshotImage ) ++ { ++ bHasLiveImages = true; ++ break; ++ } ++ } ++ } ++ if ( bHasLiveImages ) ++ g_device.waitIdle(); + + pOutput->nOutImage = 0; + +@@ -3386,7 +3400,8 @@ bool vulkan_remake_output_images() + { + pOutput->outputImages.clear(); + pOutput->outputImagesPartialOverlay.clear(); +- pOutput->temporaryHackyBlankImage = vulkan_create_debug_blank_texture(); ++ if ( GetBackend()->IsSessionBased() || !pOutput->temporaryHackyBlankImage ) ++ pOutput->temporaryHackyBlankImage = vulkan_create_debug_blank_texture(); + return true; + } +