mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-12 03:21:08 +00:00
perf(gamescope): handle a finished frame at import (0124) with upstream fence fixes (0123)
0123 backports upstream 0efe47c and 666c52b by Matthew Schwartz (commit completion list lifetime, no Rc to a dying commit). 0124 polls a new commit's fence at import; a finished frame is marked done at once and handled in the same steamcompmgr pass instead of a second wake through the image waiter. commit_ready_check (default on) turns it off.
This commit is contained in:
1 parent
4ef6b53eb0
commit
f7cebee7ee
3 files changed
+278
No files matched your search
@@ -181,3 +181,21 @@ The nested Wayland backend's input thread reads the host display, but steamcompm
|
||||
does not watch that file descriptor, so buffer releases and presentation feedback
|
||||
queued by that read could wait up to one refresh for steamcompmgr's next poll. The
|
||||
input thread now wakes steamcompmgr after each read.
|
||||
|
||||
## 0123 commit: fence lifetime fixes from upstream
|
||||
|
||||
Backport of upstream commits 0efe47c and 666c52b by Matthew Schwartz (ValveSoftware/gamescope).
|
||||
Pending commits share ownership of their completion list with the Xwayland context, so a late
|
||||
fence signal can no longer append to a list freed with the context; and a commit being destroyed
|
||||
no longer hands the image waiter a new reference to itself. Both touch the code 0124 changes.
|
||||
|
||||
## 0124 commit: mark a finished frame done at import
|
||||
|
||||
Every game frame took two passes of steamcompmgr's loop: the import duplicated the buffer's
|
||||
fence and handed the commit to the image waiter (epoll add), then the waiter thread saw the fence
|
||||
signalled, removed and closed it and woke steamcompmgr again to handle the finished commit.
|
||||
`update_wayland_res` now polls the fence without waiting first. A frame that is already finished
|
||||
is marked done at once - no duplicate fence, no epoll add or delete, no waiter wake - and the main
|
||||
loop handles it in the same pass, after the import (FIFO commits still wait for a vblank). The
|
||||
`commit_ready_check` convar (default on, `gamescopectl commit_ready_check 0`) turns it off; the
|
||||
`xwm` log counts fences ready at import and waited for, every 10 s.
|
||||
@@ -0,0 +1,157 @@
|
||||
diff --git a/src/commit.cpp b/src/commit.cpp
|
||||
index c9d0001..f2e0f0c 100644
|
||||
--- a/src/commit.cpp
|
||||
+++ b/src/commit.cpp
|
||||
@@ -105,14 +105,15 @@ bool commit_t::CloseFenceInternal()
|
||||
if ( m_nCommitFence < 0 )
|
||||
return false;
|
||||
|
||||
- // Will automatically remove from epoll!
|
||||
- g_ImageWaiter.RemoveWaitable( this );
|
||||
+ // Do not recreate an Rc after deletion has started.
|
||||
+ if ( HasLiveReferences() )
|
||||
+ g_ImageWaiter.RemoveWaitable( this );
|
||||
close( m_nCommitFence );
|
||||
m_nCommitFence = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
-void commit_t::SetFence( int nFence, bool bMangoNudge, uint32_t uMangoMsgType, CommitDoneList_t *pDoneCommits )
|
||||
+void commit_t::SetFence( int nFence, bool bMangoNudge, uint32_t uMangoMsgType, const std::shared_ptr<CommitDoneList_t> &pDoneCommits )
|
||||
{
|
||||
std::unique_lock lock( m_WaitableCommitStateMutex );
|
||||
CloseFenceInternal();
|
||||
diff --git a/src/commit.h b/src/commit.h
|
||||
index 20f881d..8603a9a 100644
|
||||
--- a/src/commit.h
|
||||
+++ b/src/commit.h
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "steamcompmgr_shared.hpp"
|
||||
#include "Utils/NonCopyable.h"
|
||||
|
||||
+#include <memory>
|
||||
#include <optional>
|
||||
#include "main.hpp"
|
||||
#include "rendervulkan.hpp"
|
||||
@@ -34,7 +35,7 @@ struct commit_t final : public gamescope::RcObject, public gamescope::IWaitable,
|
||||
|
||||
// Returns true if we had a fence that was closed.
|
||||
bool CloseFenceInternal();
|
||||
- void SetFence( int nFence, bool bMangoNudge, uint32_t uMangoMsgType, CommitDoneList_t *pDoneCommits );
|
||||
+ void SetFence( int nFence, bool bMangoNudge, uint32_t uMangoMsgType, const std::shared_ptr<CommitDoneList_t> &pDoneCommits );
|
||||
|
||||
bool ShouldPreemptivelyUpscale( GamescopeUpscaleFilter eFilter, GamescopeUpscaleScaler eScaler );
|
||||
|
||||
@@ -81,5 +82,5 @@ struct commit_t final : public gamescope::RcObject, public gamescope::IWaitable,
|
||||
bool m_bMangoNudge = false;
|
||||
// Typed mangoapp stream to nudge, 0 for none, never the legacy type.
|
||||
uint32_t m_uMangoMsgType = 0;
|
||||
- CommitDoneList_t *m_pDoneCommits = nullptr; // I hate this
|
||||
-};
|
||||
\ No newline at end of file
|
||||
+ std::shared_ptr<CommitDoneList_t> m_pDoneCommits; // I hate this
|
||||
+};
|
||||
diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp
|
||||
index 5fb9086..22aa907 100644
|
||||
--- a/src/steamcompmgr.cpp
|
||||
+++ b/src/steamcompmgr.cpp
|
||||
@@ -932,7 +932,7 @@ constexpr const T& clamp( const T& x, const T& min, const T& max )
|
||||
|
||||
extern bool g_bForceRelativeMouse;
|
||||
|
||||
-CommitDoneList_t g_steamcompmgr_xdg_done_commits;
|
||||
+std::shared_ptr<CommitDoneList_t> g_steamcompmgr_xdg_done_commits = std::make_shared<CommitDoneList_t>();
|
||||
|
||||
|
||||
static std::mutex s_KeysToCloseMutex;
|
||||
@@ -8073,7 +8073,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, bool vblank, uint64_t vblank_idx )
|
||||
{
|
||||
- std::lock_guard<std::mutex> lock( ctx->doneCommits.listCommitsDoneLock );
|
||||
+ std::lock_guard<std::mutex> lock( ctx->doneCommits->listCommitsDoneLock );
|
||||
|
||||
uint64_t next_refresh_time = g_SteamCompMgrVBlankTime.schedule.ulTargetVBlank;
|
||||
|
||||
@@ -8090,7 +8090,7 @@ void handle_done_commits_xwayland( xwayland_ctx_t *ctx, bool vblank, uint64_t vb
|
||||
uint64_t now = get_time_in_nanos();
|
||||
|
||||
// very fast loop yes
|
||||
- for ( auto& entry : ctx->doneCommits.listCommitsDone )
|
||||
+ for ( auto& entry : ctx->doneCommits->listCommitsDone )
|
||||
{
|
||||
steamcompmgr_win_t *entry_win = nullptr;
|
||||
for ( steamcompmgr_win_t *w = ctx->list; w; w = w->xwayland().next )
|
||||
@@ -8130,12 +8130,12 @@ void handle_done_commits_xwayland( xwayland_ctx_t *ctx, bool vblank, uint64_t vb
|
||||
}
|
||||
}
|
||||
|
||||
- ctx->doneCommits.listCommitsDone.swap( commits_before_their_time );
|
||||
+ ctx->doneCommits->listCommitsDone.swap( commits_before_their_time );
|
||||
}
|
||||
|
||||
void handle_done_commits_xdg( bool vblank, uint64_t vblank_idx )
|
||||
{
|
||||
- std::lock_guard<std::mutex> lock( g_steamcompmgr_xdg_done_commits.listCommitsDoneLock );
|
||||
+ std::lock_guard<std::mutex> lock( g_steamcompmgr_xdg_done_commits->listCommitsDoneLock );
|
||||
|
||||
uint64_t next_refresh_time = g_SteamCompMgrVBlankTime.schedule.ulTargetVBlank;
|
||||
|
||||
@@ -8152,7 +8152,7 @@ void handle_done_commits_xdg( bool vblank, uint64_t vblank_idx )
|
||||
uint64_t now = get_time_in_nanos();
|
||||
|
||||
// very fast loop yes
|
||||
- for ( auto& entry : g_steamcompmgr_xdg_done_commits.listCommitsDone )
|
||||
+ for ( auto& entry : g_steamcompmgr_xdg_done_commits->listCommitsDone )
|
||||
{
|
||||
steamcompmgr_win_t *entry_win = nullptr;
|
||||
for (const auto& xdg_win : g_steamcompmgr_xdg_wins)
|
||||
@@ -8192,7 +8192,7 @@ void handle_done_commits_xdg( bool vblank, uint64_t vblank_idx )
|
||||
}
|
||||
}
|
||||
|
||||
- g_steamcompmgr_xdg_done_commits.listCommitsDone.swap( commits_before_their_time );
|
||||
+ g_steamcompmgr_xdg_done_commits->listCommitsDone.swap( commits_before_their_time );
|
||||
}
|
||||
|
||||
gamescope::ConVar<bool> cv_mangoapp_use_output_timing{ "mangoapp_use_output_timing", true };
|
||||
@@ -8359,7 +8359,7 @@ static TempUpscaleImage_t *GetTempUpscaleImage( global_focus_t *pFocus, uint32_t
|
||||
|
||||
gamescope::ConVar<bool> cv_surface_update_force_only_current_surface( "surface_update_force_only_current_surface", false, "Force updates to apply only to the current surface, ignoring commits for other surfaces." );
|
||||
|
||||
-void update_wayland_res(CommitDoneList_t *doneCommits, steamcompmgr_win_t *w, ResListEntry_t& reslistentry)
|
||||
+void update_wayland_res(const std::shared_ptr<CommitDoneList_t> &doneCommits, steamcompmgr_win_t *w, ResListEntry_t& reslistentry)
|
||||
{
|
||||
struct wlr_buffer *buf = reslistentry.buf;
|
||||
|
||||
@@ -8632,7 +8632,7 @@ void check_new_xwayland_res(xwayland_ctx_t *ctx)
|
||||
for ( uint32_t i = 0; i < tmp_queue.size(); i++ )
|
||||
{
|
||||
steamcompmgr_win_t *w = find_win( ctx, tmp_queue[ i ].surf );
|
||||
- update_wayland_res( &ctx->doneCommits, w, tmp_queue[ i ]);
|
||||
+ update_wayland_res( ctx->doneCommits, w, tmp_queue[ i ]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8645,7 +8645,7 @@ void check_new_xdg_res()
|
||||
{
|
||||
if ( xdg_win->xdg().surface.main_surface == tmp_queue[ i ].surf )
|
||||
{
|
||||
- update_wayland_res( &g_steamcompmgr_xdg_done_commits, xdg_win.get(), tmp_queue[ i ] );
|
||||
+ update_wayland_res( g_steamcompmgr_xdg_done_commits, xdg_win.get(), tmp_queue[ i ] );
|
||||
break;
|
||||
}
|
||||
}
|
||||
diff --git a/src/xwayland_ctx.hpp b/src/xwayland_ctx.hpp
|
||||
index 81910a1..3a75650 100644
|
||||
--- a/src/xwayland_ctx.hpp
|
||||
+++ b/src/xwayland_ctx.hpp
|
||||
@@ -92,7 +92,7 @@ struct xwayland_ctx_t final : public gamescope::IWaitable
|
||||
|
||||
std::unique_ptr<MouseCursor> cursor;
|
||||
|
||||
- CommitDoneList_t doneCommits;
|
||||
+ std::shared_ptr<CommitDoneList_t> doneCommits = std::make_shared<CommitDoneList_t>();
|
||||
|
||||
double accum_x = 0.0;
|
||||
double accum_y = 0.0;
|
||||
@@ -0,0 +1,103 @@
|
||||
diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp
|
||||
index 22aa907..0aef598 100644
|
||||
--- a/src/steamcompmgr.cpp
|
||||
+++ b/src/steamcompmgr.cpp
|
||||
@@ -8359,6 +8359,33 @@ static TempUpscaleImage_t *GetTempUpscaleImage( global_focus_t *pFocus, uint32_t
|
||||
|
||||
gamescope::ConVar<bool> cv_surface_update_force_only_current_surface( "surface_update_force_only_current_surface", false, "Force updates to apply only to the current surface, ignoring commits for other surfaces." );
|
||||
|
||||
+gamescope::ConVar<bool> cv_commit_ready_check( "commit_ready_check", true, "Check a new commit's fence at import; a finished frame is marked done in the same pass instead of through the image waiter." );
|
||||
+
|
||||
+// Set when update_wayland_res marks a commit done itself, so the main loop handles it in the same pass.
|
||||
+static bool s_bXwaylandCommitsDoneAtImport = false;
|
||||
+static bool s_bXdgCommitsDoneAtImport = false;
|
||||
+
|
||||
+static bool commit_fence_ready_now( int nFd )
|
||||
+{
|
||||
+ struct pollfd pfd = { .fd = nFd, .events = POLLIN, .revents = 0 };
|
||||
+ return poll( &pfd, 1, 0 ) == 1 && ( pfd.revents & POLLIN );
|
||||
+}
|
||||
+
|
||||
+static void note_commit_fence( bool bReadyAtImport )
|
||||
+{
|
||||
+ static uint64_t s_ulReady = 0, s_ulWaited = 0, s_ulLastLog = 0;
|
||||
+ ( bReadyAtImport ? s_ulReady : s_ulWaited )++;
|
||||
+ uint64_t now = get_time_in_nanos();
|
||||
+ if ( !s_ulLastLog )
|
||||
+ s_ulLastLog = now;
|
||||
+ if ( now - s_ulLastLog >= 10'000'000'000ul )
|
||||
+ {
|
||||
+ xwm_log.infof( "commit fences, last 10 s: %lu ready at import, %lu waited for", s_ulReady, s_ulWaited );
|
||||
+ s_ulReady = s_ulWaited = 0;
|
||||
+ s_ulLastLog = now;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void update_wayland_res(const std::shared_ptr<CommitDoneList_t> &doneCommits, steamcompmgr_win_t *w, ResListEntry_t& reslistentry)
|
||||
{
|
||||
struct wlr_buffer *buf = reslistentry.buf;
|
||||
@@ -8602,7 +8629,11 @@ void update_wayland_res(const std::shared_ptr<CommitDoneList_t> &doneCommits, st
|
||||
struct wlr_dmabuf_attributes dmabuf = {0};
|
||||
if ( wlr_buffer_get_dmabuf( buf, &dmabuf ) )
|
||||
{
|
||||
- fence = dup( dmabuf.fd[0] );
|
||||
+ // A finished buffer needs no fence of its own.
|
||||
+ if ( cv_commit_ready_check && commit_fence_ready_now( dmabuf.fd[0] ) )
|
||||
+ bKnownReady = true;
|
||||
+ else
|
||||
+ fence = dup( dmabuf.fd[0] );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -8610,11 +8641,22 @@ void update_wayland_res(const std::shared_ptr<CommitDoneList_t> &doneCommits, st
|
||||
}
|
||||
}
|
||||
|
||||
+ if ( cv_commit_ready_check )
|
||||
+ {
|
||||
+ if ( !bKnownReady && fence >= 0 && commit_fence_ready_now( fence ) )
|
||||
+ bKnownReady = true;
|
||||
+ note_commit_fence( bKnownReady );
|
||||
+ }
|
||||
+
|
||||
gpuvis_trace_printf( "pushing wait for commit %lu win %lx", newCommit->commitID, w->type == steamcompmgr_win_type_t::XWAYLAND ? w->xwayland().id : 0 );
|
||||
{
|
||||
newCommit->SetFence( fence, mango_nudge, uMangoMsgType, doneCommits );
|
||||
if ( bKnownReady )
|
||||
+ {
|
||||
newCommit->Signal();
|
||||
+ if ( cv_commit_ready_check )
|
||||
+ ( w->type == steamcompmgr_win_type_t::XWAYLAND ? s_bXwaylandCommitsDoneAtImport : s_bXdgCommitsDoneAtImport ) = true;
|
||||
+ }
|
||||
else
|
||||
g_ImageWaiter.AddWaitable( newCommit.get() );
|
||||
}
|
||||
@@ -9400,6 +9442,13 @@ void steamcompmgr_check_xdg(bool vblank, uint64_t vblank_idx)
|
||||
}
|
||||
|
||||
check_new_xdg_res();
|
||||
+
|
||||
+ // Commits marked done at import: handle them now rather than on the next wake. FIFO commits still wait for a vblank.
|
||||
+ if ( s_bXdgCommitsDoneAtImport )
|
||||
+ {
|
||||
+ s_bXdgCommitsDoneAtImport = false;
|
||||
+ handle_done_commits_xdg( false, vblank_idx );
|
||||
+ }
|
||||
}
|
||||
|
||||
void update_edid_prop()
|
||||
@@ -10512,6 +10561,14 @@ steamcompmgr_main(int argc, char **argv)
|
||||
gamescope_xwayland_server_t *server = NULL;
|
||||
for (size_t i = 0; (server = wlserver_get_xwayland_server(i)); i++)
|
||||
check_new_xwayland_res(server->ctx.get());
|
||||
+
|
||||
+ // Commits marked done at import: handle them now rather than on the next wake. FIFO commits still wait for a vblank.
|
||||
+ if ( s_bXwaylandCommitsDoneAtImport )
|
||||
+ {
|
||||
+ s_bXwaylandCommitsDoneAtImport = false;
|
||||
+ for (size_t i = 0; (server = wlserver_get_xwayland_server(i)); i++)
|
||||
+ handle_done_commits_xwayland(server->ctx.get(), false, vblank_idx);
|
||||
+ }
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user