steamcompmgr: Implement dynamic refresh rate based on FPS limit

Adds a mode to dynamically change the refresh rate based on the existing FPS limit.
This commit is contained in:
Joshua Ashton 2022-01-31 23:05:22 +00:00 committed by Joshie
parent c5ab6f388b
commit 6d2cb3073c
4 changed files with 39 additions and 0 deletions

View file

@ -1533,3 +1533,19 @@ bool drm_set_resolution( struct drm_t *drm, int width, int height )
return drm_set_mode(drm, mode);
}
int drm_get_default_refresh(struct drm_t *drm)
{
if ( drm->preferred_refresh )
return drm->preferred_refresh;
if ( drm->connector && drm->connector->connector )
{
drmModeConnector *connector = drm->connector->connector;
const drmModeModeInfo *mode = find_mode( connector, g_nOutputWidth, g_nOutputHeight, 0);
if ( mode )
return mode->vrefresh;
}
return 60;
}

View file

@ -162,3 +162,4 @@ bool drm_set_color_gain_blend(struct drm_t *drm, float blend);
bool drm_update_gamma_lut(struct drm_t *drm);
char *find_drm_node_by_devid(dev_t devid);
int drm_get_default_refresh(struct drm_t *drm);

View file

@ -229,6 +229,10 @@ std::mutex g_FrameLimitCommitsMutex;
std::queue< std::shared_ptr<commit_t> > g_FrameLimitCommits;
static int g_nSteamCompMgrTargetFPS = 0;
static uint64_t g_uDynamicRefreshEqualityTime = 0;
static bool g_bDynamicRefreshEnabled = false;
// Delay to stop modes flickering back and forth.
static const uint64_t g_uDynamicRefreshDelay = 600'000'000; // 600ms
bool steamcompmgr_window_should_limit_fps( win *w )
{
@ -1714,6 +1718,18 @@ paint_all()
const bool bOverrideCompositeHack = false;
#endif
int nTargetRefresh = g_nSteamCompMgrTargetFPS && g_bDynamicRefreshEnabled && steamcompmgr_window_should_limit_fps( global_focus.focusWindow ) && !global_focus.overlayWindow
? g_nSteamCompMgrTargetFPS
: drm_get_default_refresh( &g_DRM );
uint64_t now = get_time_in_nanos();
if ( g_nOutputRefresh == nTargetRefresh )
g_uDynamicRefreshEqualityTime = now;
if ( !BIsNested() && g_nOutputRefresh != nTargetRefresh && g_uDynamicRefreshEqualityTime + g_uDynamicRefreshDelay < now )
drm_set_refresh( &g_DRM, nTargetRefresh );
bool bNeedsNearest = !g_bFilterGameWindow && composite.data.vScale[0].x != 1.0f && composite.data.vScale[0].y != 1.0f;
bool bNeedsComposite = BIsNested();
@ -3719,6 +3735,10 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev)
{
steamcompmgr_set_target_fps( get_prop( ctx, ctx->root, ctx->atoms.gamescopeFPSLimit, 0 ) );
}
if ( ev->atom == ctx->atoms.gamescopeDynamicRefresh )
{
g_bDynamicRefreshEnabled = !!get_prop( ctx, ctx->root, ctx->atoms.gamescopeDynamicRefresh, 0 );
}
}
static int
@ -4576,6 +4596,7 @@ void init_xwayland_ctx(gamescope_xwayland_server_t *xwayland_server)
ctx->atoms.gamescopeColorLinearGainBlend = XInternAtom( ctx->dpy, "GAMESCOPE_COLOR_LINEARGAIN_BLEND", false );
ctx->atoms.gamescopeXWaylandModeControl = XInternAtom( ctx->dpy, "GAMESCOPE_XWAYLAND_MODE_CONTROL", false );
ctx->atoms.gamescopeFPSLimit = XInternAtom( ctx->dpy, "GAMESCOPE_FPS_LIMIT", false );
ctx->atoms.gamescopeDynamicRefresh = XInternAtom( ctx->dpy, "GAMESCOPE_DYNAMIC_REFRESH", false );
ctx->root_width = DisplayWidth(ctx->dpy, ctx->scr);
ctx->root_height = DisplayHeight(ctx->dpy, ctx->scr);

View file

@ -123,5 +123,6 @@ struct xwayland_ctx_t
Atom gamescopeXWaylandModeControl;
Atom gamescopeFPSLimit;
Atom gamescopeDynamicRefresh;
} atoms;
};