Skip to content

Commit

Permalink
wlserver, layer: Fix layer + Tom Clancy's Rainbow Six Extraction
Browse files Browse the repository at this point in the history
Game has multiple swapchains for one window, yikes!

Take whoever committed last.
  • Loading branch information
Joshua-Ashton committed Mar 8, 2024
1 parent 8670c93 commit 9563271
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 38 deletions.
28 changes: 24 additions & 4 deletions layer/VkLayer_FROG_gamescope_wsi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,8 @@ namespace GamescopeWSILayer {
bool isBypassingXWayland;
bool forceFifo;
VkPresentModeKHR presentMode;
uint32_t serverId = 0;
bool retired = false;

std::unique_ptr<std::mutex> presentTimingMutex = std::make_unique<std::mutex>();
std::vector<VkPastPresentationTimingGOOGLE> pastPresentTimings;
Expand Down Expand Up @@ -285,7 +287,17 @@ namespace GamescopeWSILayer {
swapchain->refreshCycle = (uint64_t(refresh_cycle_hi) << 32) | refresh_cycle_lo;
}
fprintf(stderr, "[Gamescope WSI] Swapchain recieved new refresh cycle: %.2fms\n", swapchain->refreshCycle / 1'000'000.0);
}
},

.retired = [](
void *data,
gamescope_swapchain *object) {
GamescopeSwapchainData *swapchain = reinterpret_cast<GamescopeSwapchainData*>(data);
{
swapchain->retired = true;
}
fprintf(stderr, "[Gamescope WSI] Swapchain retired\n");
},
};

class VkInstanceOverrides {
Expand Down Expand Up @@ -944,9 +956,6 @@ namespace GamescopeWSILayer {
gamescopeInstance->gamescopeSwapchainFactory,
gamescopeSurface->surface);

if (canBypass)
gamescope_swapchain_override_window_content(gamescopeSwapchainObject, *serverId, gamescopeSurface->window);

{
auto gamescopeSwapchain = GamescopeSwapchain::create(*pSwapchain, GamescopeSwapchainData{
.object = gamescopeSwapchainObject,
Expand All @@ -955,6 +964,7 @@ namespace GamescopeWSILayer {
.isBypassingXWayland = canBypass,
.forceFifo = gamescopeIsForcingFifo(), // Were we forcing fifo when this swapchain was made?
.presentMode = swapchainInfo.presentMode, // The new present mode.
.serverId = *serverId,
});
gamescopeSwapchain->pastPresentTimings.reserve(MaxPastPresentationTimes);

Expand Down Expand Up @@ -1056,6 +1066,16 @@ namespace GamescopeWSILayer {
}
}

for (uint32_t i = 0; i < presentInfo.swapchainCount; i++) {
if (auto gamescopeSwapchain = GamescopeSwapchain::get(presentInfo.pSwapchains[i])) {
auto gamescopeSurface = GamescopeSurface::get(gamescopeSwapchain->surface);
if (gamescopeSwapchain->retired)
return VK_ERROR_OUT_OF_DATE_KHR;
else if (gamescopeSurface->canBypassXWayland())
gamescope_swapchain_override_window_content(gamescopeSwapchain->object, gamescopeSwapchain->serverId, gamescopeSurface->window);
}
}

VkResult result = pDispatch->QueuePresentKHR(queue, &presentInfo);

for (uint32_t i = 0; i < presentInfo.swapchainCount; i++) {
Expand Down
4 changes: 4 additions & 0 deletions protocol/gamescope-swapchain.xml
Original file line number Diff line number Diff line change
Expand Up @@ -181,5 +181,9 @@
<arg name="refresh_cycle_hi" type="uint" summary="high part of the refresh cycle in nanos"/>
<arg name="refresh_cycle_lo" type="uint" summary="low part of the refresh cycle in nanos"/>
</event>

<event name="retired">
<description summary="Swapchain was remotely retired"></description>
</event>
</interface>
</protocol>
17 changes: 7 additions & 10 deletions src/steamcompmgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6412,18 +6412,15 @@ void handle_presented_for_window( steamcompmgr_win_t* w )
if (struct wlr_surface *surface = w->current_surface())
{
auto info = get_wl_surface_info(surface);
if (info != nullptr && info->gamescope_swapchain != nullptr && info->last_refresh_cycle != refresh_cycle)
if (info != nullptr && info->last_refresh_cycle != refresh_cycle)
{
if (info->gamescope_swapchain != nullptr)
{
// Could have got the override set in this bubble.s
surface = w->current_surface();
// Could have got the override set in this bubble.
surface = w->current_surface();

if (info->last_refresh_cycle != refresh_cycle)
{
info->last_refresh_cycle = refresh_cycle;
wlserver_refresh_cycle(surface, refresh_cycle);
}
if (info->last_refresh_cycle != refresh_cycle)
{
info->last_refresh_cycle = refresh_cycle;
wlserver_refresh_cycle(surface, refresh_cycle);
}
}
}
Expand Down
59 changes: 36 additions & 23 deletions src/wlserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ struct wlserver_content_override {
struct wlr_surface *surface;
uint32_t x11_window;
struct wl_listener surface_destroy_listener;
struct wl_resource *gamescope_swapchain;
};

enum wlserver_touch_click_mode g_nDefaultTouchClickMode = WLSERVER_TOUCH_CLICK_LEFT;
Expand Down Expand Up @@ -532,6 +533,10 @@ static struct wl_listener new_surface_listener = { .notify = wlserver_new_surfac

void gamescope_xwayland_server_t::destroy_content_override( struct wlserver_content_override *co )
{
if ( co->gamescope_swapchain )
{
gamescope_swapchain_send_retired(co->gamescope_swapchain);
}
wl_list_remove( &co->surface_destroy_listener.link );
content_overrides.erase( co->x11_window );
free( co );
Expand All @@ -546,6 +551,7 @@ void gamescope_xwayland_server_t::destroy_content_override( struct wlserver_x11_
x11_surface->override_surface = nullptr;

struct wlserver_content_override *co = iter->second;
co->gamescope_swapchain = nullptr;
if (co->surface == surf)
destroy_content_override(iter->second);
}
Expand All @@ -561,18 +567,22 @@ static void content_override_handle_surface_destroy( struct wl_listener *listene

void gamescope_xwayland_server_t::handle_override_window_content( struct wl_client *client, struct wl_resource *resource, struct wlr_surface *surface, uint32_t x11_window )
{
if ( content_overrides.count( x11_window ) ) {
destroy_content_override( content_overrides[ x11_window ] );
}
wlserver_x11_surface_info *x11_surface = lookup_x11_surface_info_from_xid( this, x11_window );
// If we found an x11_surface, go back up to our parent.
if ( x11_surface )
x11_window = x11_surface->x11_id;

if ( content_overrides.count( x11_window ) ) {
if ( content_overrides[x11_window]->gamescope_swapchain == resource )
return;
destroy_content_override( content_overrides[ x11_window ] );
}

struct wlserver_content_override *co = (struct wlserver_content_override *)calloc(1, sizeof(*co));
co->server = this;
co->surface = surface;
co->x11_window = x11_window;
co->gamescope_swapchain = resource;
co->surface_destroy_listener.notify = content_override_handle_surface_destroy;
wl_signal_add( &surface->events.destroy, &co->surface_destroy_listener );
content_overrides[ x11_window ] = co;
Expand Down Expand Up @@ -682,8 +692,7 @@ static void gamescope_swapchain_destroy( struct wl_client *client, struct wl_res
if (x11_surface)
x11_surface->xwayland_server->destroy_content_override( x11_surface, wl_surface_info->wlr );

if (wl_surface_info->gamescope_swapchain == resource)
wl_surface_info->gamescope_swapchain = nullptr;
std::erase(wl_surface_info->gamescope_swapchains, resource);

wl_resource_destroy( resource );
}
Expand Down Expand Up @@ -810,10 +819,10 @@ static void gamescope_swapchain_factory_create_swapchain( struct wl_client *clie
= wl_resource_create( client, &gamescope_swapchain_interface, wl_resource_get_version( resource ), id );
wl_resource_set_implementation( gamescope_swapchain_resource, &gamescope_swapchain_impl, wl_surface_info, NULL );

if (wl_surface_info->gamescope_swapchain != nullptr)
wl_log.errorf("create_swapchain: Surface already had a gamescope_swapchain! Overriding.");
if (wl_surface_info->gamescope_swapchains.size())
wl_log.errorf("create_swapchain: Surface already had a gamescope_swapchain! Warning!");

wl_surface_info->gamescope_swapchain = gamescope_swapchain_resource;
wl_surface_info->gamescope_swapchains.emplace_back( gamescope_swapchain_resource );
}

static const struct gamescope_swapchain_factory_interface gamescope_swapchain_factory_impl = {
Expand Down Expand Up @@ -1278,17 +1287,19 @@ void wlserver_past_present_timing( struct wlr_surface *surface, uint32_t present
if ( !wl_info )
return;

gamescope_swapchain_send_past_present_timing(
wl_info->gamescope_swapchain,
present_id,
desired_present_time >> 32,
desired_present_time & 0xffffffff,
actual_present_time >> 32,
actual_present_time & 0xffffffff,
earliest_present_time >> 32,
earliest_present_time & 0xffffffff,
present_margin >> 32,
present_margin & 0xffffffff);
for (auto& swapchain : wl_info->gamescope_swapchains) {
gamescope_swapchain_send_past_present_timing(
swapchain,
present_id,
desired_present_time >> 32,
desired_present_time & 0xffffffff,
actual_present_time >> 32,
actual_present_time & 0xffffffff,
earliest_present_time >> 32,
earliest_present_time & 0xffffffff,
present_margin >> 32,
present_margin & 0xffffffff);
}
}

void wlserver_refresh_cycle( struct wlr_surface *surface, uint64_t refresh_cycle )
Expand All @@ -1297,10 +1308,12 @@ void wlserver_refresh_cycle( struct wlr_surface *surface, uint64_t refresh_cycle
if ( !wl_info )
return;

gamescope_swapchain_send_refresh_cycle(
wl_info->gamescope_swapchain,
refresh_cycle >> 32,
refresh_cycle & 0xffffffff);
for (auto& swapchain : wl_info->gamescope_swapchains) {
gamescope_swapchain_send_refresh_cycle(
swapchain,
refresh_cycle >> 32,
refresh_cycle & 0xffffffff);
}
}

///////////////////////
Expand Down
2 changes: 1 addition & 1 deletion src/wlserver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ struct wlserver_wl_surface_info
uint64_t sequence = 0;
std::vector<struct wl_resource*> pending_presentation_feedbacks;

std::atomic<struct wl_resource *> gamescope_swapchain = { nullptr };
std::vector<struct wl_resource *> gamescope_swapchains;
std::optional<uint32_t> present_id = std::nullopt;
uint64_t desired_present_time = 0;

Expand Down

0 comments on commit 9563271

Please sign in to comment.