r.OneFrameThreadLag

r.OneFrameThreadLag

#Overview

name: r.OneFrameThreadLag

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

It is referenced in 8 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of r.OneFrameThreadLag is to control whether the rendering thread is allowed to lag one frame behind the game thread in Unreal Engine 5. This setting is primarily used for managing the synchronization between the game and rendering threads.

This setting variable is utilized by multiple Unreal Engine subsystems, including:

  1. The core engine loop (LaunchEngineLoop.cpp)
  2. The Slate rendering system (SlateRHIRenderer.cpp and SlateNullRenderer.cpp)

The value of this variable is set through a console variable (CVar) system. It’s defined in UnrealEngine.cpp with a default value of 1 (enabled).

The associated variable CVarAllowOneFrameThreadLag interacts directly with r.OneFrameThreadLag. They share the same value and are used interchangeably in the code.

Developers must be aware that:

  1. This setting affects the synchronization between game and render threads, which can impact performance and visual consistency.
  2. When enabled (value != 0), it allows the rendering thread to lag one frame behind the game thread, potentially improving performance at the cost of increased input latency.
  3. When disabled (value == 0), it enforces strict synchronization between game and render threads, which may impact performance but ensures frame-accurate rendering.

Best practices when using this variable include:

  1. Test your game with both enabled and disabled states to understand the impact on performance and visual quality.
  2. Consider disabling it for games that require frame-accurate rendering or minimal input latency.
  3. Use profiling tools to measure the impact of this setting on your specific game’s performance.

Regarding the associated variable CVarAllowOneFrameThreadLag:

The purpose of CVarAllowOneFrameThreadLag is to provide a programmatic way to access and modify the r.OneFrameThreadLag setting within the engine’s C++ code. It’s used in the same subsystems and modules as r.OneFrameThreadLag.

The value of CVarAllowOneFrameThreadLag is set when the engine initializes the console variable system. It’s accessed using IConsoleManager::Get().FindTConsoleVariableDataInt() in various parts of the engine code.

Developers should be aware that modifying CVarAllowOneFrameThreadLag at runtime will have the same effect as changing r.OneFrameThreadLag through the console or configuration files. The same best practices apply to both variables.

#References in C++ code

#Callsites

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

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

Scope: file

Source code excerpt:


TAutoConsoleVariable<int32> CVarAllowOneFrameThreadLag(
	TEXT("r.OneFrameThreadLag"),
	1,
	TEXT("Whether to allow the rendering thread to lag one frame behind the game thread (0: disabled, otherwise enabled)")
);

static FAutoConsoleVariable CVarSystemResolution(
	TEXT("r.SetRes"),

#Loc: <Workspace>/Engine/Source/Runtime/Launch/Private/LaunchEngineLoop.cpp:6143

Scope: file

Source code excerpt:

			// Sync game and render thread. Either total sync or allowing one frame lag.
			static FFrameEndSync FrameEndSync;
			static auto CVarAllowOneFrameThreadLag = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.OneFrameThreadLag"));
			FrameEndSync.Sync( CVarAllowOneFrameThreadLag->GetValueOnGameThread() != 0 );
		}

		// tick core ticker, threads & deferred commands
		{
			SCOPE_CYCLE_COUNTER(STAT_DeferredTickTime);

#Loc: <Workspace>/Engine/Source/Runtime/SlateNullRenderer/Private/SlateNullRenderer.cpp:141

Scope (from outer to inner):

file
function     void FSlateNullRenderer::Sync

Source code excerpt:

	// Sync game and render thread. Either total sync or allowing one frame lag.
	static FFrameEndSync FrameEndSync;
	static auto CVarAllowOneFrameThreadLag = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.OneFrameThreadLag"));
	FrameEndSync.Sync(CVarAllowOneFrameThreadLag->GetValueOnAnyThread() != 0);
#endif
}

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

Scope (from outer to inner):

file
function     void FSlateRHIRenderer::Sync

Source code excerpt:

	// Sync game and render thread. Either total sync or allowing one frame lag.
	static FFrameEndSync FrameEndSync;
	static auto CVarAllowOneFrameThreadLag = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.OneFrameThreadLag"));
	FrameEndSync.Sync(CVarAllowOneFrameThreadLag->GetValueOnAnyThread() != 0);
}

/**
 * Inline issues a BeginFrame to the RHI.
 * This is to handle cases like Modal dialogs in the UI. The game loop stops while

#Associated Variable and Callsites

This variable is associated with another variable named CVarAllowOneFrameThreadLag. They share the same value. See the following C++ source code.

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

Scope: file

Source code excerpt:

ENGINE_API int32 GUnbuiltHLODCount = 0;

TAutoConsoleVariable<int32> CVarAllowOneFrameThreadLag(
	TEXT("r.OneFrameThreadLag"),
	1,
	TEXT("Whether to allow the rendering thread to lag one frame behind the game thread (0: disabled, otherwise enabled)")
);

static FAutoConsoleVariable CVarSystemResolution(

#Loc: <Workspace>/Engine/Source/Runtime/Launch/Private/LaunchEngineLoop.cpp:6143

Scope: file

Source code excerpt:

			// Sync game and render thread. Either total sync or allowing one frame lag.
			static FFrameEndSync FrameEndSync;
			static auto CVarAllowOneFrameThreadLag = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.OneFrameThreadLag"));
			FrameEndSync.Sync( CVarAllowOneFrameThreadLag->GetValueOnGameThread() != 0 );
		}

		// tick core ticker, threads & deferred commands
		{
			SCOPE_CYCLE_COUNTER(STAT_DeferredTickTime);
			CSV_SCOPED_TIMING_STAT_EXCLUSIVE(DeferredTickTime);

#Loc: <Workspace>/Engine/Source/Runtime/SlateNullRenderer/Private/SlateNullRenderer.cpp:141

Scope (from outer to inner):

file
function     void FSlateNullRenderer::Sync

Source code excerpt:

	// Sync game and render thread. Either total sync or allowing one frame lag.
	static FFrameEndSync FrameEndSync;
	static auto CVarAllowOneFrameThreadLag = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.OneFrameThreadLag"));
	FrameEndSync.Sync(CVarAllowOneFrameThreadLag->GetValueOnAnyThread() != 0);
#endif
}

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

Scope (from outer to inner):

file
function     void FSlateRHIRenderer::Sync

Source code excerpt:

	// Sync game and render thread. Either total sync or allowing one frame lag.
	static FFrameEndSync FrameEndSync;
	static auto CVarAllowOneFrameThreadLag = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.OneFrameThreadLag"));
	FrameEndSync.Sync(CVarAllowOneFrameThreadLag->GetValueOnAnyThread() != 0);
}

/**
 * Inline issues a BeginFrame to the RHI.
 * This is to handle cases like Modal dialogs in the UI. The game loop stops while
 * the dialog is open but continues to issue draws. The RHI thinks there are all part of one super long