Release 1.1.3 with game window and Gamescope lifecycle fixes
This commit is contained in:
@@ -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 {
|
||||
80
native/gamescope/patches/gamescope-lazy-output-images.patch
Normal file
80
native/gamescope/patches/gamescope-lazy-output-images.patch
Normal file
@@ -0,0 +1,80 @@
|
||||
From: Matthew Schwartz <matthew.schwartz@linux.dev>
|
||||
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<uint64_t> vulkan_composite( struct FrameInfo_t *frameInfo, gamesco
|
||||
g_reshadeManager.clear();
|
||||
}
|
||||
|
||||
+ if ( !pOutputOverride && !vulkan_ensure_output_images() )
|
||||
+ return std::nullopt;
|
||||
+
|
||||
gamescope::Rc<CVulkanTexture> compositeImage;
|
||||
if ( pOutputOverride )
|
||||
compositeImage = pOutputOverride;
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<std::shared_ptr<zwp_relative_pointer_v1>> m_pRelativePointer = nullptr;
|
||||
std::unordered_set<uint32_t> m_uScancodesHeld;
|
||||
+ std::unordered_set<uint32_t> 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 )
|
||||
{
|
||||
50
native/gamescope/patches/gamescope-wayland-live-resize.patch
Normal file
50
native/gamescope/patches/gamescope-wayland-live-resize.patch
Normal file
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user