Skip to content

Commit

Permalink
vblankmanager: Rework redzone + drawtime on VRR to be tight
Browse files Browse the repository at this point in the history
We don't want to push forward and pre-empt things at all in VRR, we only use fixed refreshes in order to be able to push overlays.

If we pre-empt too much, we risk going above 2 refresh cycles for overlay updates and causing stutters.
  • Loading branch information
misyltoad committed Aug 20, 2024
1 parent cf74874 commit f554d88
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 15 deletions.
30 changes: 16 additions & 14 deletions src/vblankmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,23 +99,24 @@ namespace gamescope

const int nRefreshRate = GetRefresh();
const uint64_t ulRefreshInterval = mHzToRefreshCycle( nRefreshRate );
// The redzone is relative to 60Hz for external displays.
// Scale it by our target refresh so we don't miss submitting for
// vblank in DRM.
// (This fixes wonky frame-pacing on 4K@30Hz screens)
//
// TODO(Josh): Is this fudging still needed with our SteamOS kernel patches
// to not account for vertical front porch when dealing with the vblank
// drm_commit is going to target?
// Need to re-test that.
const uint64_t ulRedZone = eScreenType == GAMESCOPE_SCREEN_TYPE_INTERNAL
? m_ulVBlankDrawBufferRedZone
: std::min<uint64_t>( m_ulVBlankDrawBufferRedZone, ( m_ulVBlankDrawBufferRedZone * 60'000 * nRefreshRate ) / 60'000 );

bool bVRR = GetBackend()->IsVRRActive();
uint64_t ulOffset = 0;
if ( !bVRR )
{
// The redzone is relative to 60Hz for external displays.
// Scale it by our target refresh so we don't miss submitting for
// vblank in DRM.
// (This fixes wonky frame-pacing on 4K@30Hz screens)
//
// TODO(Josh): Is this fudging still needed with our SteamOS kernel patches
// to not account for vertical front porch when dealing with the vblank
// drm_commit is going to target?
// Need to re-test that.
const uint64_t ulRedZone = eScreenType == GAMESCOPE_SCREEN_TYPE_INTERNAL
? m_ulVBlankDrawBufferRedZone
: std::min<uint64_t>( m_ulVBlankDrawBufferRedZone, ( m_ulVBlankDrawBufferRedZone * 60'000 * nRefreshRate ) / 60'000 );

const uint64_t ulDecayAlpha = m_ulVBlankRateOfDecayPercentage; // eg. 980 = 98%

uint64_t ulDrawTime = m_ulLastDrawTime;
Expand Down Expand Up @@ -162,8 +163,9 @@ namespace gamescope
m_ulRollingMaxDrawTime = kStartingVBlankDrawTime;
}

// TODO(Josh): We can probably do better than this for VRR.
uint64_t ulDrawTime = kVRRFlushingDrawTime;
uint64_t ulRedZone = kVRRFlushingTime;

uint64_t ulDrawTime = 0;
/// See comment of m_ulVBlankDrawTimeMinCompositing.
if ( m_bCurrentlyCompositing )
ulDrawTime = std::max( ulDrawTime, m_ulVBlankDrawTimeMinCompositing );
Expand Down
2 changes: 1 addition & 1 deletion src/vblankmanager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ namespace gamescope
static constexpr uint64_t kDefaultVBlankRateOfDecayPercentage = 980ul; // 98%
static constexpr uint64_t kVBlankRateOfDecayMax = 1000ul; // 100%

static constexpr uint64_t kVRRFlushingDrawTime = 1'000'000; // Could possibly be lower, like 300'000 or something.
static constexpr uint64_t kVRRFlushingTime = 300'000;

CVBlankTimer();
~CVBlankTimer();
Expand Down

1 comment on commit f554d88

@Lawstorant
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finally! VRR + HDR works. Tested on 6800XT + Ultrawide OLED monitor.

Please sign in to comment.