From 6d2cb3073c42b74c0f28c372f71ac158378fe616 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Mon, 31 Jan 2022 23:05:22 +0000 Subject: [PATCH] steamcompmgr: Implement dynamic refresh rate based on FPS limit Adds a mode to dynamically change the refresh rate based on the existing FPS limit. --- src/drm.cpp | 16 ++++++++++++++++ src/drm.hpp | 1 + src/steamcompmgr.cpp | 21 +++++++++++++++++++++ src/xwayland_ctx.hpp | 1 + 4 files changed, 39 insertions(+) diff --git a/src/drm.cpp b/src/drm.cpp index 9da45eb..1e805df 100644 --- a/src/drm.cpp +++ b/src/drm.cpp @@ -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; +} \ No newline at end of file diff --git a/src/drm.hpp b/src/drm.hpp index d73e5c9..77841f0 100644 --- a/src/drm.hpp +++ b/src/drm.hpp @@ -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); \ No newline at end of file diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp index a8b51dd..b1a22b4 100644 --- a/src/steamcompmgr.cpp +++ b/src/steamcompmgr.cpp @@ -229,6 +229,10 @@ std::mutex g_FrameLimitCommitsMutex; std::queue< std::shared_ptr > 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); diff --git a/src/xwayland_ctx.hpp b/src/xwayland_ctx.hpp index d99461a..06c6672 100644 --- a/src/xwayland_ctx.hpp +++ b/src/xwayland_ctx.hpp @@ -123,5 +123,6 @@ struct xwayland_ctx_t Atom gamescopeXWaylandModeControl; Atom gamescopeFPSLimit; + Atom gamescopeDynamicRefresh; } atoms; };