r.VSync

r.VSync

#Overview

name: r.VSync

The value of this variable can be defined or overridden in .ini config files. 3 .ini config files referencing this setting variable.

This variable is created as a Console Variable (cvar).

It is referenced in 19 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of r.VSync is to control vertical synchronization (VSync) in the rendering system of Unreal Engine 5. It is a console variable that can be set to enable or disable VSync, which synchronizes the frame rate of the game with the refresh rate of the display to prevent screen tearing.

This setting variable is primarily used by the rendering subsystem of Unreal Engine, but it also interacts with various other modules and plugins, including:

  1. Core Engine
  2. RenderGrid plugin
  3. AjaMedia plugin
  4. BlackmagicMedia plugin
  5. Dynamic Resolution system
  6. Game User Settings
  7. GPU Profiler
  8. Rendering Thread management
  9. Slate RHI Renderer

The value of this variable is typically set through the console or configuration files. It can also be modified programmatically using the console variable system.

Other variables that interact with r.VSync include:

Developers should be aware of the following when using this variable:

  1. Enabling VSync (setting to 1) can impact performance and increase input lag.
  2. VSync may interfere with certain time-sensitive operations, such as genlock in media capture scenarios.
  3. It can affect GPU profiling results, potentially skewing timing data.
  4. It interacts with dynamic resolution and frame rate limiting features.

Best practices when using this variable include:

  1. Consider disabling VSync during performance profiling to get more accurate results.
  2. Be cautious when using VSync in conjunction with custom time steps or media capture features.
  3. Remember to account for VSync when implementing frame rate management or dynamic resolution systems.
  4. When developing multi-display or specialized rendering setups, carefully consider the implications of VSync on synchronization across displays.

#Setting Variables

#References In INI files

Location: <Workspace>/Engine/Config/BaseEngine.ini:2214, section: [SystemSettingsEditor]

Location: <Workspace>/Engine/Config/Android/AndroidEngine.ini:74, section: [ConsoleVariables]

Location: <Workspace>/Projects/Lyra/Config/DefaultDeviceProfiles.ini:57, section: [Mobile DeviceProfile]

#References in C++ code

#Callsites

This variable is referenced in the following C++ source code:

#Loc: <Workspace>/Engine/Source/Runtime/Core/Private/HAL/ConsoleManager.cpp:3834

Scope: file

Source code excerpt:


static TAutoConsoleVariable<int32> CVarSetVSyncEnabled(
	TEXT("r.VSync"),
	0,
	TEXT("0: VSync is disabled.(default)\n"
		 "1: VSync is enabled."),
	ECVF_Scalability | ECVF_RenderThreadSafe);

#if WITH_EDITOR

#Loc: <Workspace>/Engine/Plugins/Experimental/RenderGrid/Source/RenderGrid/Private/Utils/RenderGridUtils.cpp:428

Scope (from outer to inner):

file
function     FRenderGridPreviousEngineFpsSettings UE::RenderGrid::Private::FRenderGridUtils::DisableFpsLimit

Source code excerpt:

	if (GEngine)
	{
		static IConsoleVariable* VSync = IConsoleManager::Get().FindConsoleVariable(TEXT("r.VSync"));
		static IConsoleVariable* VSyncEditor = IConsoleManager::Get().FindConsoleVariable(TEXT("r.VSyncEditor"));
		UEditorPerformanceSettings* EditorPerformanceSettings = GetMutableDefault<UEditorPerformanceSettings>();

		Settings.bHasBeenSet = true;
		Settings.bUseFixedFrameRate = GEngine->bUseFixedFrameRate;
		Settings.bForceDisableFrameRateSmoothing = GEngine->bForceDisableFrameRateSmoothing;

#Loc: <Workspace>/Engine/Plugins/Experimental/RenderGrid/Source/RenderGrid/Private/Utils/RenderGridUtils.cpp:455

Scope (from outer to inner):

file
function     void UE::RenderGrid::Private::FRenderGridUtils::RestoreFpsLimit

Source code excerpt:

	if (GEngine && Settings.bHasBeenSet)
	{
		static IConsoleVariable* VSync = IConsoleManager::Get().FindConsoleVariable(TEXT("r.VSync"));
		static IConsoleVariable* VSyncEditor = IConsoleManager::Get().FindConsoleVariable(TEXT("r.VSyncEditor"));
		UEditorPerformanceSettings* EditorPerformanceSettings = GetMutableDefault<UEditorPerformanceSettings>();

		GEngine->bUseFixedFrameRate = Settings.bUseFixedFrameRate;
		GEngine->bForceDisableFrameRateSmoothing = Settings.bForceDisableFrameRateSmoothing;
		GEngine->SetMaxFPS(Settings.MaxFps);

#Loc: <Workspace>/Engine/Plugins/Experimental/RenderGrid/Source/RenderGrid/Public/Utils/RenderGridUtils.h:37

Scope (from outer to inner):

file
function     struct RENDERGRID_API FRenderGridPreviousEngineFpsSettings { GENERATED_BODY

Source code excerpt:

	float MaxFps = 0;

	/** The previous value of console variable "r.VSync". */
	UPROPERTY()
	bool bVSync = false;

	/** The previous value of console variable "r.VSyncEditor". */
	UPROPERTY()
	bool bVSyncEditor = false;

#Loc: <Workspace>/Engine/Plugins/Media/AjaMedia/Source/AjaMedia/Private/Assets/AjaCustomTimeStep.cpp:313

Scope (from outer to inner):

file
function     bool UAjaCustomTimeStep::UpdateTimeStep

Source code excerpt:

	// Warn about Vsync once
	{
		static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.VSync"));
		if (!bWarnedAboutVSync)
		{
			bool bLockToVsync = CVar->GetValueOnGameThread() != 0;
			if (bLockToVsync)
			{
				UE_LOG(LogAjaMedia, Warning, TEXT("The Engine is using VSync and may break the 'genlock'"));

#Loc: <Workspace>/Engine/Plugins/Media/AjaMedia/Source/AjaMediaOutput/Private/AjaMediaCapture.cpp:550

Scope (from outer to inner):

file
function     bool UAjaMediaCapture::InitAJA

Source code excerpt:

	if (bWaitForSyncEvent)
	{
		const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.VSync"));
		bool bLockToVsync = CVar->GetValueOnGameThread() != 0;
		if (bLockToVsync)
		{
			UE_LOG(LogAjaMediaOutput, Warning, TEXT("The Engine use VSync and something wants to wait for the sync event. This may break the \"gen-lock\"."));
		}

#Loc: <Workspace>/Engine/Plugins/Media/BlackmagicMedia/Source/BlackmagicMedia/Private/Assets/BlackmagicCustomTimeStep.cpp:320

Scope (from outer to inner):

file
function     bool UBlackmagicCustomTimeStep::UpdateTimeStep

Source code excerpt:

	if (CurrentState == ECustomTimeStepSynchronizationState::Synchronized)
	{
		static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.VSync"));
		if (!bWarnedAboutVSync)
		{
			bool bLockToVsync = CVar->GetValueOnGameThread() != 0;
			if (bLockToVsync)
			{
				UE_LOG(LogBlackmagicMedia, Warning, TEXT("The Engine is using VSync and may break the 'genlock'"));

#Loc: <Workspace>/Engine/Plugins/Media/BlackmagicMedia/Source/BlackmagicMediaOutput/Private/BlackmagicMediaCapture.cpp:712

Scope (from outer to inner):

file
function     bool UBlackmagicMediaCapture::InitBlackmagic

Source code excerpt:

	if (bSuccess && bWaitForSyncEvent)
	{
		const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.VSync"));
		bool bLockToVsync = CVar->GetValueOnGameThread() != 0;
		if (bLockToVsync)
		{
			UE_LOG(LogBlackmagicMediaOutput, Warning, TEXT("The Engine use VSync and something to wait for the sync event. This may break the \"gen-lock\"."));
		}

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/DynamicResolution.cpp:77

Scope: file

Source code excerpt:

	ECVF_RenderThreadSafe | ECVF_Default);

/** On desktop, the swap chain doesn't allow tear amount configuration, so an overbudget frame can be droped with r.VSync=1.
 * So need to lower the heuristic's target budget to lower chances to go overbudget.
 *
 * Moreover the GPU is a shared ressource with other process which may or may not be included in our GPU timings,
 * and need to leave some GPU capacity to these application to not get preempted by OS scheduler.
 * Given we can measure other application's GPU cost, need to leave enough headroom for them all the time.
 */
static TAutoConsoleVariable<float> CVarOverBudgetGPUHeadRoomPercentage(
	TEXT("r.DynamicRes.OverBudgetGPUHeadRoomPercentage"),
	0.0f,
	TEXT("Amount of GPU headroom needed from which the frame is considered over budget. This is for platform not supporting controllable tearing with VSync (in percent from r.DynamicRes.FrameTimeBudget)."),
	ECVF_RenderThreadSafe | ECVF_Default);

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/DynamicResolution.cpp:283

Scope (from outer to inner):

file
function     void FDynamicResolutionHeuristicProxy::RefreshCurrentFrameResolutionFraction_RenderThread

Source code excerpt:

	if (CVarDynamicFrameTimeEnable.GetValueOnRenderThread())
	{
		static const IConsoleVariable* VSyncCVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.VSync"));
		check(VSyncCVar);

		const int32 FrameTimeTrack = CVarDynamicFrameTimeTrack.GetValueOnRenderThread();

		// Find out the frame time that should be used.
		TArray<float, TInlineAllocator<16>> SortedFrameTime;

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/GameUserSettings.cpp:181

Scope (from outer to inner):

file
function     bool UGameUserSettings::IsVSyncDirty

Source code excerpt:

	if (GEngine && GEngine->GameViewport && GEngine->GameViewport->ViewportFrame)
	{
		static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.VSync"));
		bIsDirty = (bUseVSync != (CVar->GetValueOnAnyThread() != 0));
	}
	return bIsDirty;
}

bool UGameUserSettings::IsDynamicResolutionDirty() const

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/GameUserSettings.cpp:376

Scope (from outer to inner):

file
function     void UGameUserSettings::ValidateSettings

Source code excerpt:

			// Force reset if there aren't any default .ini settings.
			SetToDefaults();
			static const auto CVarVSync = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.VSync"));
			SetVSyncEnabled(CVarVSync->GetValueOnGameThread() != 0);

			if (GEngine)
			{
				SetDynamicResolutionEnabled(GEngine->GetDynamicResolutionUserSetting());
			}

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/GameUserSettings.cpp:445

Scope (from outer to inner):

file
function     void UGameUserSettings::ApplyNonResolutionSettings

Source code excerpt:

		else
		{
			static auto CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.VSync"));
			CVar->Set(IsVSyncEnabled(), ECVF_SetByGameSetting);
		}
	}

	GEngine->SetDynamicResolutionUserSetting(IsDynamicResolutionEnabled());

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/GameUserSettings.cpp:743

Scope (from outer to inner):

file
function     void UGameUserSettings::ResetToCurrentSettings

Source code excerpt:


		// Set the current VSync state
		static const auto CVarVSync = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.VSync"));
		SetVSyncEnabled(CVarVSync->GetValueOnGameThread() != 0);

		// Set the current dynamic resolution state
		SetDynamicResolutionEnabled(GEngine->GetDynamicResolutionUserSetting());

		// Reset confirmed settings

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/UnrealClient.cpp:1709

Scope (from outer to inner):

file
function     void FViewport::Draw

Source code excerpt:

			if( SizeX > 0 && SizeY > 0 )
			{
				static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.VSync"));
				bool bLockToVsync = CVar->GetValueOnGameThread() != 0;
				ULocalPlayer* Player = (GEngine && World) ? GEngine->GetFirstGamePlayer(World) : NULL;
				if ( Player )
				{
					bLockToVsync |= (Player && Player->PlayerController && Player->PlayerController->bCinematicMode);
				}

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/UnrealEngine.cpp:680

Scope (from outer to inner):

file
function     void CalculateFPSTimings

Source code excerpt:


	static auto CVarGTSyncType = IConsoleManager::Get().FindConsoleVariable(TEXT("r.GTSyncType"));
	static auto CVarVsync = IConsoleManager::Get().FindConsoleVariable(TEXT("r.VSync"));
	if (CVarGTSyncType->GetInt() == 2 && CVarVsync->GetInt() != 0)
	{
		float RHIFrameTime = RHIGetFrameTime();
		if (RHIFrameTime != 0)
		{
			FrameTimeMS = RHIFrameTime;

#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/GPUProfiler.cpp:479

Scope (from outer to inner):

file
function     void FGPUProfilerEventNodeFrame::DumpEventTree

Source code excerpt:

		// Display a warning if this is a GPU profile and the GPU was profiled with v-sync enabled
		FText VsyncEnabledWarningText = FText::GetEmpty();
		static IConsoleVariable* CVSyncVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.VSync"));
		if (CVSyncVar->GetInt() != 0 && !PlatformDisablesVSync())
		{
			VsyncEnabledWarningText = LOCTEXT("GpuProfileVsyncEnabledWarning", "WARNING: This GPU profile was captured with v-sync enabled.  V-sync wait time may show up in any bucket, and as a result the data in this profile may be skewed. Please profile with v-sync disabled to obtain the most accurate data.");
			UE_LOG(LogRHI, Log, TEXT("%s"), *(VsyncEnabledWarningText.ToString()));
		}

#Loc: <Workspace>/Engine/Source/Runtime/RenderCore/Private/RenderingThread.cpp:1215

Scope (from outer to inner):

file
function     void FRenderCommandFence::BeginFence

Source code excerpt:

		// Don't sync to the RHI and GPU if GtSyncType is disabled, or we're not vsyncing
		//@TODO: do this logic in the caller?
		static auto CVarVsync = IConsoleManager::Get().FindConsoleVariable(TEXT("r.VSync"));
		check(CVarVsync != nullptr);

		if (GTSyncType == 0 || CVarVsync->GetInt() == 0)
		{
			bSyncToRHIAndGPU = false;
		}

#Loc: <Workspace>/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateRHIRenderer.cpp:1748

Scope (from outer to inner):

file
function     void FSlateRHIRenderer::DrawWindows_Private

Source code excerpt:

				else
				{
					static IConsoleVariable* CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.VSync"));
					bForceVsyncFromCVar = (CVar->GetInt() != 0);
				}

				bLockToVsync |= bForceVsyncFromCVar;

				// Cache if the element batcher post buffer usage, will get reset on batch reset