From 7d14f9f4652d8267e747ad4838a6c829825e82b0 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 24 Nov 2023 13:29:37 +0100 Subject: [PATCH 1/4] steamcompmgr: add per-window sequence number This is guaranteed to never be re-used. --- src/steamcompmgr.cpp | 3 +++ src/steamcompmgr.hpp | 1 + src/steamcompmgr_shared.hpp | 2 ++ src/wlserver.cpp | 1 + 4 files changed, 7 insertions(+) diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp index 1c6ed8d63a..925d0dc593 100644 --- a/src/steamcompmgr.cpp +++ b/src/steamcompmgr.cpp @@ -130,6 +130,8 @@ extern float g_flInternalDisplayBrightnessNits; extern float g_flHDRItmSdrNits; extern float g_flHDRItmTargetNits; +uint64_t g_lastWinSeq = 0; + extern std::atomic g_lastVblank; static std::shared_ptr s_scRGB709To2020Matrix; @@ -4580,6 +4582,7 @@ add_win(xwayland_ctx_t *ctx, Window id, Window prev, unsigned long sequence) if (!new_win) return; + new_win->seq = ++g_lastWinSeq; new_win->type = steamcompmgr_win_type_t::XWAYLAND; new_win->_window_types.emplace(); diff --git a/src/steamcompmgr.hpp b/src/steamcompmgr.hpp index fb8a5d2814..e77665afcb 100644 --- a/src/steamcompmgr.hpp +++ b/src/steamcompmgr.hpp @@ -140,6 +140,7 @@ extern float focusedWindowOffsetY; extern bool g_bFSRActive; extern uint32_t inputCounter; +extern uint64_t g_lastWinSeq; void nudge_steamcompmgr( void ); void take_screenshot( int flags = TAKE_SCREENSHOT_BASEPLANE_ONLY ); diff --git a/src/steamcompmgr_shared.hpp b/src/steamcompmgr_shared.hpp index 2b0f2e4ef7..3bcdb16e82 100644 --- a/src/steamcompmgr_shared.hpp +++ b/src/steamcompmgr_shared.hpp @@ -90,6 +90,8 @@ struct steamcompmgr_xdg_win_t struct steamcompmgr_win_t { unsigned int opacity; + uint64_t seq; + std::shared_ptr title; bool utf8_title; pid_t pid; diff --git a/src/wlserver.cpp b/src/wlserver.cpp index 49f96ed62f..5547f347f5 100644 --- a/src/wlserver.cpp +++ b/src/wlserver.cpp @@ -1367,6 +1367,7 @@ void xdg_surface_new(struct wl_listener *listener, void *data) wlserver.xdg_wins.emplace_back(window); } + window->seq = ++g_lastWinSeq; window->type = steamcompmgr_win_type_t::XDG; window->_window_types.emplace(); From 51b871ef5965194b4a72b143d69169e69841886f Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 24 Nov 2023 13:34:37 +0100 Subject: [PATCH 2/4] steamcompmgr: track window for each commit --- src/steamcompmgr.cpp | 10 +++++++--- src/xwayland_ctx.hpp | 1 + 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp index 925d0dc593..5263cf92da 100644 --- a/src/steamcompmgr.cpp +++ b/src/steamcompmgr.cpp @@ -757,6 +757,7 @@ struct commit_t : public gamescope::IWaitable bool async = false; std::optional feedback = std::nullopt; + uint64_t win_seq = 0; struct wlr_surface *surf = nullptr; std::vector presentation_feedbacks; @@ -793,7 +794,7 @@ struct commit_t : public gamescope::IWaitable // When we get the new IWaitable stuff in there. { std::unique_lock< std::mutex > lock( pDoneCommits->listCommitsDoneLock ); - pDoneCommits->listCommitsDone.push_back( CommitDoneEntry_t{ commitID, desired_present_time } ); + pDoneCommits->listCommitsDone.push_back( CommitDoneEntry_t{ win_seq, commitID, desired_present_time } ); } if ( m_bMangoNudge ) @@ -1366,11 +1367,12 @@ destroy_buffer( struct wl_listener *listener, void * ) } static std::shared_ptr -import_commit ( struct wlr_surface *surf, struct wlr_buffer *buf, bool async, std::shared_ptr swapchain_feedback, std::vector presentation_feedbacks, std::optional present_id, uint64_t desired_present_time ) +import_commit ( steamcompmgr_win_t *w, struct wlr_surface *surf, struct wlr_buffer *buf, bool async, std::shared_ptr swapchain_feedback, std::vector presentation_feedbacks, std::optional present_id, uint64_t desired_present_time ) { std::shared_ptr commit = std::make_shared(); std::unique_lock lock( wlr_buffer_map_lock ); + commit->win_seq = w->seq; commit->surf = surf; commit->buf = buf; commit->async = async; @@ -6392,6 +6394,8 @@ void handle_done_commits_xwayland( xwayland_ctx_t *ctx ) for ( steamcompmgr_win_t *w = ctx->list; w; w = w->xwayland().next ) { + if (w->seq != entry.winSeq) + continue; if (handle_done_commit(w, ctx, entry.commitID, entry.earliestPresentTime, entry.earliestLatchTime)) break; } @@ -6578,7 +6582,7 @@ void update_wayland_res(CommitDoneList_t *doneCommits, steamcompmgr_win_t *w, Re return; } - std::shared_ptr newCommit = import_commit( reslistentry.surf, buf, reslistentry.async, std::move(reslistentry.feedback), std::move(reslistentry.presentation_feedbacks), reslistentry.present_id, reslistentry.desired_present_time ); + std::shared_ptr newCommit = import_commit( w, reslistentry.surf, buf, reslistentry.async, std::move(reslistentry.feedback), std::move(reslistentry.presentation_feedbacks), reslistentry.present_id, reslistentry.desired_present_time ); int fence = -1; if ( newCommit ) diff --git a/src/xwayland_ctx.hpp b/src/xwayland_ctx.hpp index f4704f869f..c57630d655 100644 --- a/src/xwayland_ctx.hpp +++ b/src/xwayland_ctx.hpp @@ -35,6 +35,7 @@ struct focus_t struct CommitDoneEntry_t { + uint64_t winSeq; uint64_t commitID; uint64_t desiredPresentTime; uint64_t earliestPresentTime; From a6e32c6d54e0e23f3abac0cd4ab39996acbe6901 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 24 Nov 2023 14:11:01 +0100 Subject: [PATCH 3/4] Update wlroots to v0.18 --- src/meson.build | 2 +- src/wlserver.cpp | 22 +++++++++------------- src/wlserver.hpp | 2 +- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/meson.build b/src/meson.build index d3dec0d2fe..f0d99d5319 100644 --- a/src/meson.build +++ b/src/meson.build @@ -22,7 +22,7 @@ stb_dep = dependency('stb') wlroots_dep = dependency( 'wlroots', - version: ['>= 0.17.0', '< 0.18.0'], + version: ['>= 0.18.0', '< 0.19.0'], fallback: ['wlroots', 'wlroots'], default_options: ['default_library=static', 'examples=false', 'xwayland=enabled', 'backends=libinput', 'renderers=[]', 'allocators=[]', 'session=enabled'], ) diff --git a/src/wlserver.cpp b/src/wlserver.cpp index 5547f347f5..807eb29195 100644 --- a/src/wlserver.cpp +++ b/src/wlserver.cpp @@ -1177,7 +1177,8 @@ bool wlsession_init( void ) { if ( BIsNested() ) return true; - wlserver.wlr.session = wlr_session_create( wlserver.display ); + auto loop = wl_display_get_event_loop( wlserver.display ); + wlserver.wlr.session = wlr_session_create( loop ); if ( wlserver.wlr.session == nullptr ) { wl_log.errorf( "Failed to create session" ); @@ -1265,7 +1266,7 @@ gamescope_xwayland_server_t::gamescope_xwayland_server_t(wl_display *display) update_output_info(); - wlr_output_create_global(output); + wlr_output_create_global(output, wlserver.display); } gamescope_xwayland_server_t::~gamescope_xwayland_server_t() @@ -1344,15 +1345,10 @@ static void xdg_toplevel_destroy(struct wl_listener *listener, void *data) { wlserver_surface->xdg_surface = nullptr; } -void xdg_surface_new(struct wl_listener *listener, void *data) +void xdg_toplevel_new(struct wl_listener *listener, void *data) { - struct wlr_xdg_surface *xdg_surface = (struct wlr_xdg_surface *)data; - - if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) - { - wl_log.infof("Not top level surface."); - return; - } + struct wlr_xdg_toplevel *xdg_toplevel = (struct wlr_xdg_toplevel *)data; + struct wlr_xdg_surface *xdg_surface = xdg_toplevel->base; wlserver_wl_surface_info *wlserver_surface = get_wl_surface_info(xdg_surface->surface); if (!wlserver_surface) @@ -1377,7 +1373,7 @@ void xdg_surface_new(struct wl_listener *listener, void *data) wlserver_xdg_surface_info* xdg_surface_info = &window->xdg().surface; xdg_surface_info->main_surface = xdg_surface->surface; xdg_surface_info->win = window.get(); - xdg_surface_info->xdg_toplevel = xdg_surface->toplevel; + xdg_surface_info->xdg_toplevel = xdg_toplevel; wlserver_surface->xdg_surface = xdg_surface_info; @@ -1468,8 +1464,8 @@ bool wlserver_init( void ) { wl_log.infof("Unable to create XDG shell interface"); return false; } - wlserver.new_xdg_surface.notify = xdg_surface_new; - wl_signal_add(&wlserver.xdg_shell->events.new_surface, &wlserver.new_xdg_surface); + wlserver.new_xdg_toplevel.notify = xdg_toplevel_new; + wl_signal_add(&wlserver.xdg_shell->events.new_toplevel, &wlserver.new_xdg_toplevel); int result = -1; int display_slot = 0; diff --git a/src/wlserver.hpp b/src/wlserver.hpp index 07f36d6140..d4f34bfa51 100644 --- a/src/wlserver.hpp +++ b/src/wlserver.hpp @@ -131,7 +131,7 @@ struct wlserver_t { struct wl_listener new_input_method; struct wlr_xdg_shell *xdg_shell; - struct wl_listener new_xdg_surface; + struct wl_listener new_xdg_toplevel; std::vector> xdg_wins; std::atomic xdg_dirty; std::mutex xdg_commit_lock; From 820278e091d49247ffffcf86bceb47175704c153 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 24 Nov 2023 14:35:41 +0100 Subject: [PATCH 4/4] Add support for commit-queue-v1 --- protocol/meson.build | 1 + src/steamcompmgr.cpp | 31 ++++++++++++++++++++++++++----- src/wlserver.cpp | 7 +++++++ src/wlserver.hpp | 1 + src/xwayland_ctx.hpp | 1 + 5 files changed, 36 insertions(+), 5 deletions(-) diff --git a/protocol/meson.build b/protocol/meson.build index df11a728b0..7c08b855b2 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -14,6 +14,7 @@ protocols = [ # Upstream protocols wl_protocol_dir / 'stable/xdg-shell/xdg-shell.xml', wl_protocol_dir / 'stable/presentation-time/presentation-time.xml', + wl_protocol_dir / 'staging/commit-queue/commit-queue-v1.xml', # Gamescope protocols 'gamescope-xwayland.xml', diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp index 5263cf92da..6821d2d095 100644 --- a/src/steamcompmgr.cpp +++ b/src/steamcompmgr.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -755,6 +756,7 @@ struct commit_t : public gamescope::IWaitable uint64_t commitID = 0; bool done = false; bool async = false; + bool fifo = false; std::optional feedback = std::nullopt; uint64_t win_seq = 0; @@ -794,7 +796,12 @@ struct commit_t : public gamescope::IWaitable // When we get the new IWaitable stuff in there. { std::unique_lock< std::mutex > lock( pDoneCommits->listCommitsDoneLock ); - pDoneCommits->listCommitsDone.push_back( CommitDoneEntry_t{ win_seq, commitID, desired_present_time } ); + pDoneCommits->listCommitsDone.push_back( CommitDoneEntry_t{ + .winSeq = win_seq, + .commitID = commitID, + .desiredPresentTime = desired_present_time, + .fifo = fifo, + } ); } if ( m_bMangoNudge ) @@ -1367,7 +1374,7 @@ destroy_buffer( struct wl_listener *listener, void * ) } static std::shared_ptr -import_commit ( steamcompmgr_win_t *w, struct wlr_surface *surf, struct wlr_buffer *buf, bool async, std::shared_ptr swapchain_feedback, std::vector presentation_feedbacks, std::optional present_id, uint64_t desired_present_time ) +import_commit ( steamcompmgr_win_t *w, struct wlr_surface *surf, struct wlr_buffer *buf, bool async, std::shared_ptr swapchain_feedback, std::vector presentation_feedbacks, std::optional present_id, uint64_t desired_present_time, bool fifo ) { std::shared_ptr commit = std::make_shared(); std::unique_lock lock( wlr_buffer_map_lock ); @@ -1376,6 +1383,7 @@ import_commit ( steamcompmgr_win_t *w, struct wlr_surface *surf, struct wlr_buff commit->surf = surf; commit->buf = buf; commit->async = async; + commit->fifo = fifo; commit->presentation_feedbacks = std::move(presentation_feedbacks); if (swapchain_feedback) commit->feedback = *swapchain_feedback; @@ -6366,7 +6374,7 @@ bool handle_done_commit( steamcompmgr_win_t *w, xwayland_ctx_t *ctx, uint64_t co } // TODO: Merge these two functions. -void handle_done_commits_xwayland( xwayland_ctx_t *ctx ) +void handle_done_commits_xwayland( xwayland_ctx_t *ctx, bool vblank ) { std::lock_guard lock( ctx->doneCommits.listCommitsDoneLock ); @@ -6375,11 +6383,20 @@ void handle_done_commits_xwayland( xwayland_ctx_t *ctx ) // commits that were not ready to be presented based on their display timing. std::vector< CommitDoneEntry_t > commits_before_their_time; + // windows in FIFO mode we got a new frame to present for this vblank + std::unordered_set< uint64_t > fifo_win_seqs; + uint64_t now = get_time_in_nanos(); // very fast loop yes for ( auto& entry : ctx->doneCommits.listCommitsDone ) { + if (entry.fifo && (!vblank || fifo_win_seqs.count(entry.winSeq) > 0)) + { + commits_before_their_time.push_back( entry ); + continue; + } + if (!entry.earliestPresentTime) { entry.earliestPresentTime = next_refresh_time; @@ -6397,7 +6414,11 @@ void handle_done_commits_xwayland( xwayland_ctx_t *ctx ) if (w->seq != entry.winSeq) continue; if (handle_done_commit(w, ctx, entry.commitID, entry.earliestPresentTime, entry.earliestLatchTime)) + { + if (entry.fifo) + fifo_win_seqs.insert(entry.winSeq); break; + } } } @@ -6582,7 +6603,7 @@ void update_wayland_res(CommitDoneList_t *doneCommits, steamcompmgr_win_t *w, Re return; } - std::shared_ptr newCommit = import_commit( w, reslistentry.surf, buf, reslistentry.async, std::move(reslistentry.feedback), std::move(reslistentry.presentation_feedbacks), reslistentry.present_id, reslistentry.desired_present_time ); + std::shared_ptr newCommit = import_commit( w, reslistentry.surf, buf, reslistentry.async, std::move(reslistentry.feedback), std::move(reslistentry.presentation_feedbacks), reslistentry.present_id, reslistentry.desired_present_time, reslistentry.fifo ); int fence = -1; if ( newCommit ) @@ -7925,7 +7946,7 @@ steamcompmgr_main(int argc, char **argv) gamescope_xwayland_server_t *server = NULL; for (size_t i = 0; (server = wlserver_get_xwayland_server(i)); i++) { - handle_done_commits_xwayland(server->ctx.get()); + handle_done_commits_xwayland(server->ctx.get(), vblank); // When we have observed both a complete commit and a VBlank, we should request a new frame. if (vblank) diff --git a/src/wlserver.cpp b/src/wlserver.cpp index 807eb29195..d4a3dae1cd 100644 --- a/src/wlserver.cpp +++ b/src/wlserver.cpp @@ -33,6 +33,7 @@ extern "C" { #include #include #include +#include #undef static #undef class } @@ -43,6 +44,7 @@ extern "C" { #include "gamescope-swapchain-protocol.h" #include "gamescope-tearing-control-unstable-v1-protocol.h" #include "presentation-time-protocol.h" +#include "commit-queue-v1-protocol.h" #include "wlserver.hpp" #include "drm.hpp" @@ -104,10 +106,13 @@ void gamescope_xwayland_server_t::wayland_commit(struct wlr_surface *surf, struc auto wl_surf = get_wl_surface_info( surf ); + auto queue_mode = wlr_commit_queue_v1_get_surface_mode(surf); + ResListEntry_t newEntry = { .surf = surf, .buf = buf, .async = wlserver_surface_is_async(surf), + .fifo = queue_mode == WP_COMMIT_QUEUE_V1_QUEUE_MODE_FIFO, .feedback = wlserver_surface_swapchain_feedback(surf), .presentation_feedbacks = std::move(wl_surf->pending_presentation_feedbacks), .present_id = wl_surf->present_id, @@ -1458,6 +1463,8 @@ bool wlserver_init( void ) { create_presentation_time(); + wlr_commit_queue_manager_v1_create(wlserver.display, 1); + wlserver.xdg_shell = wlr_xdg_shell_create(wlserver.display, 3); if (!wlserver.xdg_shell) { diff --git a/src/wlserver.hpp b/src/wlserver.hpp index d4f34bfa51..edefa1df91 100644 --- a/src/wlserver.hpp +++ b/src/wlserver.hpp @@ -38,6 +38,7 @@ struct ResListEntry_t { struct wlr_surface *surf; struct wlr_buffer *buf; bool async; + bool fifo; std::shared_ptr feedback; std::vector presentation_feedbacks; std::optional present_id; diff --git a/src/xwayland_ctx.hpp b/src/xwayland_ctx.hpp index c57630d655..52f42ef42d 100644 --- a/src/xwayland_ctx.hpp +++ b/src/xwayland_ctx.hpp @@ -40,6 +40,7 @@ struct CommitDoneEntry_t uint64_t desiredPresentTime; uint64_t earliestPresentTime; uint64_t earliestLatchTime; + bool fifo; }; struct CommitDoneList_t