vblankmanager: Track latent frames

This commit is contained in:
Joshua Ashton 2022-02-14 19:15:52 +00:00
parent 765ddd74b1
commit 7ec498af0a
3 changed files with 44 additions and 25 deletions

View file

@ -253,7 +253,7 @@ void steamcompmgr_fpslimit_add_commit( std::shared_ptr<commit_t> commit )
g_FrameLimitCommits.push( commit );
}
void steamcompmgr_fpslimit_release_commit( int consecutive_missed_frame_count )
bool steamcompmgr_fpslimit_release_commit( int consecutive_missed_frame_count )
{
std::unique_lock<std::mutex> lock(g_FrameLimitCommitsMutex);
@ -265,19 +265,23 @@ void steamcompmgr_fpslimit_release_commit( int consecutive_missed_frame_count )
g_FrameLimitCommits = std::queue< std::shared_ptr<commit_t> >();
g_nAppBufferCount = 0;
g_nMaxAppBufferCount = 0;
return;
return true;
}
// Only allow 1 latent buffer -- essentially go to only "double
// buffering" when we are falling behind.
if ( g_nAppBufferCount >= g_nMaxAppBufferCount - 1 )
if ( g_nAppBufferCount == g_nMaxAppBufferCount )
{
if ( !g_FrameLimitCommits.empty() )
{
g_FrameLimitCommits.pop();
g_nAppBufferCount--;
}
return false;
}
return true;
}
@ -494,13 +498,17 @@ retry:
close( entry.fence );
uint64_t now = get_time_in_nanos();
static uint64_t lastFrameTime = now;
uint64_t frametime = now - lastFrameTime;
lastFrameTime = now;
uint64_t frametime;
if ( entry.fps_nudge || entry.mangoapp_nudge )
{
uint64_t now = get_time_in_nanos();
static uint64_t lastFrameTime = now;
frametime = now - lastFrameTime;
lastFrameTime = now;
}
if ( entry.fps_nudge )
fpslimit_mark_frame();
fpslimit_mark_frame( frametime );
{
std::unique_lock< std::mutex > lock( entry.ctx->listCommitsDoneLock );

View file

@ -168,12 +168,12 @@ static std::mutex g_TargetFPSMutex;
static std::condition_variable g_TargetFPSCondition;
static int g_nFpsLimitTargetFPS = 0;
void steamcompmgr_fpslimit_release_commit( int consecutive_missed_frame_count );
bool steamcompmgr_fpslimit_release_commit( int consecutive_missed_frame_count );
void steamcompmgr_fpslimit_release_all();
void steamcompmgr_send_frame_done_to_focus_window();
// Dump some stats.
//#define FPS_LIMIT_DEBUG
#define FPS_LIMIT_DEBUG
// 1.80ms for the app's deadzone to account for varying GPU clocks, other variances, etc
uint64_t g_uFPSLimiterRedZoneNS = 1'800'000;
@ -187,6 +187,9 @@ bool g_bFPSLimitThreadRun = true;
extern bool g_bLowLatency;
uint64_t g_uFPSLimitLastFullFrameTime = 0;
uint64_t g_uFPSLimitDoneToDoneTime = 0;
void fpslimitThreadRun( void )
{
pthread_setname_np( pthread_self(), "gamescope-fps" );
@ -197,6 +200,10 @@ void fpslimitThreadRun( void )
uint64_t vblank = 0;
int consecutive_missed_frame_count = 0;
bool last_frame_was_late = false;
g_uFPSLimitLastFullFrameTime = get_time_in_nanos();
uint64_t lastFullFrameTime = 0;
uint64_t donetodonetime = 0;
bool isLatent = false;
while ( true )
{
int nTargetFPS;
@ -228,6 +235,8 @@ void fpslimitThreadRun( void )
}
}
nTargetFPS = g_nFpsLimitTargetFPS;
lastFullFrameTime = g_uFPSLimitLastFullFrameTime;
donetodonetime = g_uFPSLimitDoneToDoneTime;
}
const int refresh = g_nNestedRefresh ? g_nNestedRefresh : g_nOutputRefresh;
@ -252,7 +261,7 @@ void fpslimitThreadRun( void )
bool useFrameCallbacks = fpslimit_use_frame_callbacks_for_focus_window( nTargetFPS, 0 );
uint64_t t0 = lastCommitReleased;
uint64_t t1 = get_time_in_nanos();
uint64_t t1 = lastFullFrameTime;
// Not the actual frame time of the game
// this is the time of the amount of work a 'frame' has done.
@ -333,7 +342,7 @@ void fpslimitThreadRun( void )
if ( !no_frame )
{
mangoapp_update( targetInterval, frameTime, latency );
mangoapp_update( isLatent ? donetodonetime : targetInterval, frameTime, latency );
}
#ifdef FPS_LIMIT_DEBUG
@ -343,7 +352,7 @@ void fpslimitThreadRun( void )
sleep_until_nanos( targetPoint );
lastCommitReleased = get_time_in_nanos();
steamcompmgr_fpslimit_release_commit( consecutive_missed_frame_count );
isLatent = steamcompmgr_fpslimit_release_commit( consecutive_missed_frame_count );
// If we aren't vblank aligned, nudge ourselves to process done commits now.
if ( !useFrameCallbacks )
@ -357,16 +366,7 @@ void fpslimitThreadRun( void )
{
if ( nTargetFPS )
{
uint64_t t0 = lastCommitReleased;
uint64_t t1 = get_time_in_nanos();
uint64_t frametime = t1 - t0 + targetInterval;
uint64_t latency = uint64_t(~0ull);
if ( refresh % nTargetFPS == 0 )
latency = frametime;
mangoapp_update( frametime, frametime, latency );
mangoapp_update( donetodonetime, donetodonetime, uint64_t(~0ull) );
}
}
@ -390,13 +390,23 @@ void fpslimit_shutdown( void )
g_TargetFPSCondition.notify_all();
}
void fpslimit_mark_frame( void )
void fpslimit_mark_frame( uint64_t frametime )
{
uint64_t now = get_time_in_nanos();
{
std::unique_lock<std::mutex> lock(g_TargetFPSMutex);
g_uFPSLimitLastFullFrameTime = now;
g_uFPSLimitDoneToDoneTime = frametime;
}
g_TargetFPSCondition.notify_all();
}
bool fpslimit_use_frame_callbacks_for_focus_window( int nTargetFPS, int nVBlankCount )
{
// Avoids a race incase the surface changes
// We don't use this anymore since we force no-fifo
return true;
#if 0
if ( !nTargetFPS )
return true;
@ -412,6 +422,7 @@ bool fpslimit_use_frame_callbacks_for_focus_window( int nTargetFPS, int nVBlankC
// call them from fpslimit
return false;
}
#endif
}
// Called from steamcompmgr thread

View file

@ -15,7 +15,7 @@ extern uint64_t g_uVBlankRateOfDecayPercentage;
void fpslimit_init( void );
void fpslimit_mark_frame( void );
void fpslimit_mark_frame( uint64_t frametime );
bool fpslimit_use_frame_callbacks_for_focus_window( int nTargetFPS, int nVBlankCount );