GameVersion
GameVersion
#Overview
name: GameVersion
The value of this variable can be defined or overridden in .ini config files. 1
.ini config file referencing this setting variable.
It is referenced in 17
C++ source files.
#Summary
#Usage in the C++ source code
The purpose of GameVersion is to identify and manage different versions of the game within the Unreal Engine 5 pipeline cache system. This variable is used to ensure compatibility between cached pipeline state objects (PSOs) and the current game version.
GameVersion is primarily used in the RHI (Rendering Hardware Interface) subsystem, specifically within the pipeline file cache functionality. It’s also referenced in the ShaderPipelineCache module of the RenderCore system.
The value of GameVersion is typically set during the initialization of the PipelineFileCacheManager. By default, it uses the changelist number from the current engine version. However, this can be overridden by the game-specific code or configuration.
GameVersion interacts with other variables in the pipeline cache header, such as Magic, Version, Platform, and Guid. These variables collectively ensure that the cached PSOs are valid for the current game and engine version.
Developers must be aware that:
- Changing the GameVersion will invalidate existing pipeline caches, which can impact load times and performance until the cache is rebuilt.
- In editor builds, the GameVersion might be different from the current engine changelist to account for precompiled binaries.
Best practices when using this variable include:
- Incrementing GameVersion when making significant changes to shaders or rendering pipelines that would invalidate existing caches.
- Considering setting a custom GameVersion in the game’s configuration file (DefaultGame.ini) for more controlled versioning.
- Being cautious when merging pipeline caches from different game versions, as this can lead to incompatibilities.
By properly managing GameVersion, developers can ensure that the pipeline cache remains valid and optimized for their specific game version, balancing between performance benefits of caching and the need for up-to-date pipeline states.
#Setting Variables
#References In INI files
Location: <Workspace>/Engine/Config/BaseEngine.ini:2247, section: [OnlineSubsystemSteam]
- INI Section:
OnlineSubsystemSteam
- Raw value:
1.0.0.0
- Is Array:
False
#References in C++ code
#Callsites
This variable is referenced in the following C++ source code:
#Loc: <Workspace>/Engine/Plugins/Runtime/Steam/SteamShared/Source/SteamShared/Private/SteamSharedModule.cpp:339
Scope (from outer to inner):
file
function FSteamServerInstanceHandler::FSteamServerInstanceHandler
Source code excerpt:
// Set GameVersions
FString GameVersion;
GConfig->GetString(TEXT("OnlineSubsystemSteam"), TEXT("GameVersion"), GameVersion, GEngineIni);
if (GameVersion.Len() == 0)
{
UE_LOG(LogSteamShared, Warning, TEXT("[OnlineSubsystemSteam].GameVersion is not set. Server advertising will fail"));
}
UE_LOG(LogSteamShared, Verbose, TEXT("Initializing Steam Game Server IP: 0x%08X Port: %d QueryPort: %d"), LocalServerIP, GamePort, QueryPort);
if (SteamGameServer_Init(LocalServerIP, GamePort, QueryPort,
(bVACEnabled ? eServerModeAuthenticationAndSecure : eServerModeAuthentication),
TCHAR_TO_UTF8(*GameVersion)))
{
UE_LOG(LogSteamShared, Verbose, TEXT("Steam Dedicated Server API initialized."));
bInitialized = true;
}
else
{
#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:226
Scope: file
Source code excerpt:
uint64 Magic; // Sanity check
uint32 Version; // File version must match engine version, otherwise we ignore
uint32 GameVersion; // Same as above but game specific code can invalidate
TEnumAsByte<EShaderPlatform> Platform; // The shader platform for all referenced PSOs.
FGuid Guid; // Guid to identify the file uniquely
uint64 TableOffset; // absolute file offset to TOC
int64 LastGCUnixTime; // Last time that the cache was scanned to remove out of date elements.
friend FArchive& operator<<(FArchive& Ar, FPipelineCacheFileFormatHeader& Info)
#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:236
Scope (from outer to inner):
file
function FArchive& operator<<
Source code excerpt:
Ar << Info.Magic;
Ar << Info.Version;
Ar << Info.GameVersion;
Ar << Info.Platform;
Ar << Info.Guid;
Ar << Info.TableOffset;
if (Info.Version >= (uint32)EPipelineCacheFileFormatVersions::LastUsedTime)
{
#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:1861
Scope: file
Source code excerpt:
EStatus CacheStatus = EStatus::Unknown;
static uint32 GameVersion;
FPipelineCacheFile()
: TOCOffset(0)
, AsyncFileHandle(nullptr)
{
}
#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:1883
Scope (from outer to inner):
file
function static bool OpenPipelineFileCache
Source code excerpt:
FPipelineCacheFileFormatHeader Header = {};
*FileReader << Header;
if (Header.Magic == FPipelineCacheFileFormatMagic && Header.Version == FPipelineCacheFileFormatCurrentVersion && Header.GameVersion == GameVersion && Header.Platform == ShaderPlatform)
{
check(Header.TableOffset > 0);
check(FileReader->TotalSize() > 0);
UE_LOG(LogRHI, Log, TEXT("FPipelineCacheFile Header Game Version: %d"), Header.GameVersion);
UE_LOG(LogRHI, Log, TEXT("FPipelineCacheFile Header Engine Data Version: %d"), Header.Version);
UE_LOG(LogRHI, Log, TEXT("FPipelineCacheFile Header TOC Offset: %llu"), Header.TableOffset);
UE_LOG(LogRHI, Log, TEXT("FPipelineCacheFile File Size: %lld Bytes"), FileReader->TotalSize());
if(Header.TableOffset < (uint64)FileReader->TotalSize())
{
#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:1911
Scope (from outer to inner):
file
function static bool OpenPipelineFileCache
Source code excerpt:
bool bMagicMatch = (Header.Magic == FPipelineCacheFileFormatMagic);
bool bVersionMatch = (Header.Version == FPipelineCacheFileFormatCurrentVersion);
bool bGameVersionMatch = (Header.GameVersion == GameVersion);
bool bSPMatch = (Header.Platform == ShaderPlatform);
UE_LOG(LogRHI, Log, TEXT("FPipelineCacheFile: skipping %s (different %s%s%s%s)"), *FilePath,
bMagicMatch ? TEXT("") : TEXT(" magic"),
bVersionMatch ? TEXT("") : TEXT(" version"),
bGameVersionMatch ? TEXT("") : TEXT(" gameversion"),
bSPMatch ? TEXT("") : TEXT(" shaderplatform")
#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:1986
Scope (from outer to inner):
file
function void GarbageCollectUserCache
Source code excerpt:
*FileReader << Header;
if (!(Header.Magic == FPipelineCacheFileFormatMagic && Header.Version == FPipelineCacheFileFormatCurrentVersion && Header.GameVersion == GameVersion && Header.Platform == ShaderPlatform))
{
UE_LOG(LogRHI, Error, TEXT("File has invalid or out of date header"));
return;
}
FTimespan GCPeriod = FTimespan::FromDays(GCPeriodInDays);
#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:2384
Scope: file
Source code excerpt:
Header.Magic = FPipelineCacheFileFormatMagic;
Header.Version = FPipelineCacheFileFormatCurrentVersion;
Header.GameVersion = GameVersion;
Header.Platform = ShaderPlatform;
Header.Guid = FileGuid;
Header.TableOffset = 0;
Header.LastGCUnixTime = UnixTime;
*JournalWriter << Header;
#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:2492
Scope: file
Source code excerpt:
Header.Magic = FPipelineCacheFileFormatMagic;
Header.Version = FPipelineCacheFileFormatCurrentVersion;
Header.GameVersion = GameVersion;
Header.Platform = ShaderPlatform;
Header.Guid = FileGuid;
Header.TableOffset = 0;
Header.LastGCUnixTime = UnixTime;
*FileWriter << Header;
#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:3006
Scope: file
Source code excerpt:
}
};
uint32 FPipelineCacheFile::GameVersion = 0;
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:3107
Scope (from outer to inner):
file
function void FPipelineFileCacheManager::Initialize
Source code excerpt:
// Make enabled explicit on a flag not the existence of "FileCache" object as we are using that behind a lock and in Open / Close operations
FileCacheEnabled = ShouldEnableFileCache();
FPipelineCacheFile::GameVersion = InGameVersion;
if (FPipelineCacheFile::GameVersion == 0)
{
// Defaulting the CL is fine though
FPipelineCacheFile::GameVersion = (uint32)FEngineVersion::Current().GetChangelist();
}
SET_MEMORY_STAT(STAT_NewCachedPSOMemory, 0);
SET_MEMORY_STAT(STAT_PSOStatMemory, 0);
}
#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:4034
Scope (from outer to inner):
file
function bool FPipelineFileCacheManager::SavePipelineFileCacheFrom
Source code excerpt:
}
bool FPipelineFileCacheManager::SavePipelineFileCacheFrom(uint32 GameVersion, EShaderPlatform Platform, FString const& Path, const TSet<FPipelineCacheFileFormatPSO>& PSOs)
{
FPipelineCacheFileData Output;
Output.Header.Magic = FPipelineCacheFileFormatMagic;
Output.Header.Version = FPipelineCacheFileFormatCurrentVersion;
Output.Header.GameVersion = GameVersion;
Output.Header.Platform = Platform;
Output.Header.TableOffset = 0;
Output.Header.Guid = FGuid::NewGuid();
Output.TOC.MetaData.Reserve(PSOs.Num());
#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:4159
Scope (from outer to inner):
file
function bool FPipelineFileCacheManager::MergePipelineFileCaches
Source code excerpt:
FPipelineCacheFileData B = FPipelineCacheFileData::Open(PathB);
if (A.Header.Magic == FPipelineCacheFileFormatMagic && B.Header.Magic == FPipelineCacheFileFormatMagic && A.Header.GameVersion == B.Header.GameVersion && A.Header.Platform == B.Header.Platform && A.Header.Version == FPipelineCacheFileFormatCurrentVersion && B.Header.Version == FPipelineCacheFileFormatCurrentVersion)
{
FPipelineCacheFileData Output;
Output.Header.Magic = FPipelineCacheFileFormatMagic;
Output.Header.Version = FPipelineCacheFileFormatCurrentVersion;
Output.Header.GameVersion = A.Header.GameVersion;
Output.Header.Platform = A.Header.Platform;
Output.Header.TableOffset = 0;
Output.Header.Guid = FGuid::NewGuid();
uint32 MergeCount = 0;
for (auto const& Entry : A.TOC.MetaData)
#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:4277
Scope (from outer to inner):
file
function bool FPipelineFileCacheManager::MergePipelineFileCaches
Source code excerpt:
}
}
else if (A.Header.GameVersion != B.Header.GameVersion)
{
UE_LOG(LogRHI, Error, TEXT("Incompatible game versions: %u vs. %u."), A.Header.GameVersion, B.Header.GameVersion);
}
else if (A.Header.Platform != B.Header.Platform)
{
UE_LOG(LogRHI, Error, TEXT("Incompatible shader platforms: %s vs. %s."), *LegacyShaderPlatformToShaderFormat(A.Header.Platform).ToString(), *LegacyShaderPlatformToShaderFormat(B.Header.Platform).ToString());
}
else if (A.Header.Version != B.Header.Version)
#Loc: <Workspace>/Engine/Source/Runtime/RHI/Public/PipelineFileCache.h:323
Scope (from outer to inner):
file
class class FPipelineFileCacheManager
Source code excerpt:
public:
RHI_API static void Initialize(uint32 GameVersion);
RHI_API static void Shutdown();
RHI_API static bool LoadPipelineFileCacheInto(FString const& Path, TSet<FPipelineCacheFileFormatPSO>& PSOs);
RHI_API static bool SavePipelineFileCacheFrom(uint32 GameVersion, EShaderPlatform Platform, FString const& Path, const TSet<FPipelineCacheFileFormatPSO>& PSOs);
RHI_API static bool MergePipelineFileCaches(FString const& PathA, FString const& PathB, FPipelineFileCacheManager::PSOOrder Order, FString const& OutputPath);
/* Open the pipeline file cache for the specfied name and platform. If successful, the GUID of the game file will be returned in OutGameFileGuid */
RHI_API static bool OpenPipelineFileCache(const FString& Key, const FString& CacheName, EShaderPlatform Platform, FGuid& OutGameFileGuid);
/* Open the user pipeline file cache for the specified name and platform. The user cache is always created even if the file was not present when opened.
#Loc: <Workspace>/Engine/Source/Runtime/RenderCore/Private/ShaderPipelineCache.cpp:635
Scope (from outer to inner):
file
function int32 FShaderPipelineCache::GetGameVersionForPSOFileCache
Source code excerpt:
int32 FShaderPipelineCache::GetGameVersionForPSOFileCache()
{
int32 GameVersion = (int32)FEngineVersion::Current().GetChangelist();
#if WITH_EDITOR
// We might be using the editor built at a different (older) CL than the current sync (think precompiled binaries synced via UGS) when packaging.
// As such, don't use the current CL as it does not reflect the state of the content.
FBuildVersion BuildVersion;
if (FBuildVersion::TryRead(FBuildVersion::GetDefaultFileName(), BuildVersion))
{
#Loc: <Workspace>/Engine/Source/Runtime/RenderCore/Private/ShaderPipelineCache.cpp:648
Scope (from outer to inner):
file
function int32 FShaderPipelineCache::GetGameVersionForPSOFileCache
Source code excerpt:
if (FEngineVersion::Current().GetChangelist() >= (uint32)BuildVersion.CompatibleChangelist)
{
GameVersion = BuildVersion.Changelist;
}
}
#endif
GConfig->GetInt(FShaderPipelineCacheConstants::SectionHeading, FShaderPipelineCacheConstants::GameVersionKey, GameVersion, *GGameIni);
return GameVersion;
}
bool FShaderPipelineCache::SetGameUsageMaskWithComparison(uint64 InMask, FPSOMaskComparisonFn InComparisonFnPtr)
{
static bool bMaskChanged = false;