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..f89849fb16 100644 --- a/src/steamcompmgr.cpp +++ b/src/steamcompmgr.cpp @@ -755,6 +755,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 +795,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{ win_seq, commitID, desired_present_time } ); + pDoneCommits->listCommitsDone.push_back( CommitDoneEntry_t{ win_seq, commitID, desired_present_time, fifo } ); } if ( m_bMangoNudge ) @@ -1367,7 +1368,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 +1377,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 +6368,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 +6377,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::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 +6408,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 +6597,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 +7940,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 9c4f39b0b5..ae21d9d558 100644 --- a/src/wlserver.cpp +++ b/src/wlserver.cpp @@ -33,6 +33,7 @@ extern "C" { #include #include #include +#include #undef static #undef class } @@ -104,10 +105,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 == 1, .feedback = wlserver_surface_swapchain_feedback(surf), .presentation_feedbacks = std::move(wl_surf->pending_presentation_feedbacks), .present_id = wl_surf->present_id, diff --git a/src/wlserver.hpp b/src/wlserver.hpp index 07f36d6140..d633252982 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