MaxFeatureLevel

MaxFeatureLevel

#Overview

name: MaxFeatureLevel

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

It is referenced in 17 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of MaxFeatureLevel is to define the highest supported graphics feature level for a given platform or device in Unreal Engine 5. This variable is crucial for determining the capabilities of the rendering system and ensuring compatibility across different hardware configurations.

MaxFeatureLevel is primarily used in the RHI (Rendering Hardware Interface) subsystem and various graphics-related modules of Unreal Engine 5. It’s particularly important in the D3D11RHI and D3D12RHI modules for Windows platforms, as well as in the general RHI implementation.

The value of this variable is typically set during the initialization of the rendering device. For example, in the D3D12 implementation, it’s determined by calling the FindHighestFeatureLevel function when creating the device.

MaxFeatureLevel often interacts with other variables related to shader models, resource binding tiers, and specific hardware capabilities like wave operations or atomic64 support.

Developers should be aware that:

  1. The value of MaxFeatureLevel affects which rendering features are available in the engine.
  2. It’s platform-specific and can vary between different hardware configurations.
  3. It’s used to determine compatibility with certain shaders and rendering techniques.

Best practices when using this variable include:

  1. Always check the MaxFeatureLevel before attempting to use high-end rendering features.
  2. Design your rendering pipeline to gracefully degrade on lower feature levels.
  3. Use the DataDrivenShaderPlatformInfo system to handle platform-specific rendering capabilities.
  4. When developing for multiple platforms, consider the lowest common MaxFeatureLevel to ensure broad compatibility.

#Setting Variables

#References In INI files

<Workspace>/Engine/Config/Android/DataDrivenPlatformInfo.ini:58, section: [ShaderPlatform OPENGL_ES3_1_ANDROID]
<Workspace>/Engine/Config/Android/DataDrivenPlatformInfo.ini:76, section: [ShaderPlatform VULKAN_ES3_1_ANDROID]
<Workspace>/Engine/Config/Android/DataDrivenPlatformInfo.ini:99, section: [ShaderPlatform VULKAN_SM5_ANDROID]
<Workspace>/Engine/Config/IOS/DataDrivenPlatformInfo.ini:51, section: [ShaderPlatform METAL]
<Workspace>/Engine/Config/IOS/DataDrivenPlatformInfo.ini:63, section: [ShaderPlatform METAL_MRT]
<Workspace>/Engine/Config/IOS/DataDrivenPlatformInfo.ini:76, section: [ShaderPlatform METAL_SIM]
<Workspace>/Engine/Config/Mac/DataDrivenPlatformInfo.ini:28, section: [ShaderPlatform METAL_SM5]
<Workspace>/Engine/Config/Mac/DataDrivenPlatformInfo.ini:68, section: [ShaderPlatform METAL_SM6]
<Workspace>/Engine/Config/Mac/DataDrivenPlatformInfo.ini:114, section: [ShaderPlatform METAL_MRT_MAC]
<Workspace>/Engine/Config/Mac/DataDrivenPlatformInfo.ini:127, section: [ShaderPlatform METAL_MACES3_1]
<Workspace>/Engine/Config/TVOS/DataDrivenPlatformInfo.ini:21, section: [ShaderPlatform METAL_MRT_TVOS]
<Workspace>/Engine/Config/TVOS/DataDrivenPlatformInfo.ini:33, section: [ShaderPlatform METAL_TVOS]
<Workspace>/Engine/Config/VulkanPC/DataDrivenPlatformInfo.ini:13, section: [ShaderPlatform VULKAN_SM5]
<Workspace>/Engine/Config/VulkanPC/DataDrivenPlatformInfo.ini:144, section: [ShaderPlatform VULKAN_SM6]
<Workspace>/Engine/Config/VulkanPC/DataDrivenPlatformInfo.ini:263, section: [ShaderPlatform VULKAN_PCES3_1]
<Workspace>/Engine/Config/Windows/DataDrivenPlatformInfo.ini:37, section: [ShaderPlatform PCD3D_SM5]
<Workspace>/Engine/Config/Windows/DataDrivenPlatformInfo.ini:87, section: [ShaderPlatform PCD3D_SM6]
<Workspace>/Engine/Config/Windows/DataDrivenPlatformInfo.ini:148, section: [ShaderPlatform PCD3D_ES3_1]
<Workspace>/Engine/Config/Windows/DataDrivenPlatformInfo.ini:175, section: [ShaderPlatform OPENGL_PCES3_1]

#References in C++ code

#Callsites

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

#Loc: <Workspace>/Engine/Plugins/FX/Niagara/Source/Niagara/Public/NiagaraCommon.h:1476

Scope (from outer to inner):

file
namespace    FNiagaraUtilities
function     inline bool SupportsNiagaraRendering

Source code excerpt:

	{
		// Note:
		// IsFeatureLevelSupported does a FeatureLevel < MaxFeatureLevel(ShaderPlatform) so checking ES3.1 support will return true for SM5. I added it explicitly to be clear what we are doing.
		return true;
	}

	// When enabled log more information for the end user
#if NO_LOGGING
	inline bool LogVerboseWarnings() { return false; }

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/EditorEngine.cpp:7843

Scope (from outer to inner):

file
function     void UEditorEngine::SetPreviewPlatform

Source code excerpt:

	EShaderPlatform ShaderPlatform = NewPreviewPlatform.ShaderPlatform;
	check(FDataDrivenShaderPlatformInfo::IsValid(ShaderPlatform));
	ERHIFeatureLevel::Type MaxFeatureLevel = NewPreviewPlatform.PreviewShaderFormatName != NAME_None ? (ERHIFeatureLevel::Type)GetMaxSupportedFeatureLevel(ShaderPlatform) : ERHIFeatureLevel::SM5;
	check(NewPreviewPlatform.PreviewShaderFormatName.IsNone() || MaxFeatureLevel == NewPreviewPlatform.PreviewFeatureLevel);

	const bool bChangedPreviewShaderPlatform = NewPreviewPlatform.ShaderPlatform != PreviewPlatform.ShaderPlatform;
	const bool bChangedEffectiveShaderPlatform = bChangedPreviewShaderPlatform && (PreviewPlatform.bPreviewFeatureLevelActive || NewPreviewPlatform.bPreviewFeatureLevelActive);
	const ERHIFeatureLevel::Type EffectiveFeatureLevel = NewPreviewPlatform.GetEffectivePreviewFeatureLevel();

	if (NewPreviewPlatform.PreviewShaderFormatName != NAME_None)

#Loc: <Workspace>/Engine/Source/Runtime/D3D12RHI/Private/D3D12Adapter.cpp:271

Scope (from outer to inner):

file
function     FD3D12AdapterDesc::FD3D12AdapterDesc

Source code excerpt:

	: Desc(InDesc)
	, AdapterIndex(InAdapterIndex)
	, MaxSupportedFeatureLevel(DeviceInfo.MaxFeatureLevel)
	, MaxSupportedShaderModel(DeviceInfo.MaxShaderModel)
	, ResourceBindingTier(DeviceInfo.ResourceBindingTier)
	, ResourceHeapTier(DeviceInfo.ResourceHeapTier)
	, MaxRHIFeatureLevel(DeviceInfo.MaxRHIFeatureLevel)
	, bSupportsWaveOps(DeviceInfo.bSupportsWaveOps)
	, bSupportsAtomic64(DeviceInfo.bSupportsAtomic64)

#Loc: <Workspace>/Engine/Source/Runtime/D3D12RHI/Private/D3D12Adapter.h:37

Scope: file

Source code excerpt:

struct FD3D12DeviceBasicInfo
{
	D3D_FEATURE_LEVEL           MaxFeatureLevel;
	D3D_SHADER_MODEL            MaxShaderModel;
	D3D12_RESOURCE_BINDING_TIER ResourceBindingTier;
	D3D12_RESOURCE_HEAP_TIER    ResourceHeapTier;
	uint32                      NumDeviceNodes;
	bool                        bSupportsWaveOps;
	bool                        bSupportsAtomic64;

#Loc: <Workspace>/Engine/Source/Runtime/D3D12RHI/Private/Windows/WindowsD3D12Device.cpp:520

Scope (from outer to inner):

file
function     static bool SafeTestD3D12CreateDevice

Source code excerpt:

		if (SUCCEEDED(D3D12CreateDeviceResult))
		{
			OutInfo.MaxFeatureLevel = FindHighestFeatureLevel(Device, MinFeatureLevel);
			OutInfo.MaxShaderModel = FindHighestShaderModel(Device);
			GetResourceTiers(Device, OutInfo.ResourceBindingTier, OutInfo.ResourceHeapTier);
			OutInfo.NumDeviceNodes = Device->GetNodeCount();

			OutInfo.bSupportsWaveOps = GetSupportsWaveOps(Device);
			OutInfo.bSupportsAtomic64 = GetSupportsAtomic64(Adapter, Device);

			OutInfo.MaxRHIFeatureLevel = FindMaxRHIFeatureLevel(OutInfo.MaxFeatureLevel, OutInfo.MaxShaderModel, OutInfo.ResourceBindingTier, OutInfo.bSupportsWaveOps, OutInfo.bSupportsAtomic64);

			Device->Release();
			return true;
		}
		else
		{

#Loc: <Workspace>/Engine/Source/Runtime/D3D12RHI/Private/Windows/WindowsD3D12Device.cpp:929

Scope (from outer to inner):

file
function     void FD3D12DynamicRHIModule::FindAdapter

Source code excerpt:

				UE_LOG(LogD3D12RHI, Log,
					TEXT("  Max supported Feature Level %s, shader model %d.%d, binding tier %d, wave ops %s, atomic64 %s"),
					GetFeatureLevelString(DeviceInfo.MaxFeatureLevel),
					(DeviceInfo.MaxShaderModel >> 4), (DeviceInfo.MaxShaderModel & 0xF),
					DeviceInfo.ResourceBindingTier,
					DeviceInfo.bSupportsWaveOps ? TEXT("supported") : TEXT("unsupported"),
					DeviceInfo.bSupportsAtomic64 ? TEXT("supported") : TEXT("unsupported")
				);

#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/DataDrivenShaderPlatformInfo.cpp:137

Scope (from outer to inner):

file
function     void FGenericDataDrivenShaderPlatformInfo::SetDefaultValues

Source code excerpt:

void FGenericDataDrivenShaderPlatformInfo::SetDefaultValues()
{
	MaxFeatureLevel = ERHIFeatureLevel::Num;
	bSupportsMSAA = true;
	bSupportsDOFHybridScattering = true;
	bSupportsHZBOcclusion = true;
	bSupportsWaterIndirectDraw = true;
	bSupportsAsyncPipelineCompilation = true;
	bSupportsVertexShaderSRVs = true; // Explicitly overriden to false for ES 3.1 platforms via DDPI ini

#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/DataDrivenShaderPlatformInfo.cpp:159

Scope (from outer to inner):

file
function     void FGenericDataDrivenShaderPlatformInfo::ParseDataDrivenShaderInfo

Source code excerpt:

	checkf(!Info.ShaderFormat.IsNone(), TEXT("Missing ShaderFormat for ShaderPlatform %s  ShaderFormat %s"), *Info.Name.ToString(), *Info.ShaderFormat.ToString());

	GetFeatureLevelFromName(GetSectionString(Section, "MaxFeatureLevel"), Info.MaxFeatureLevel);

	Info.ShaderPropertiesHash = 0;
	FString ShaderPropertiesString = Info.Name.GetPlainNameString();

#define ADD_TO_PROPERTIES_STRING(SettingName, SettingValue) \
	ShaderPropertiesString += TEXT(#SettingName); \

#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/DataDrivenShaderPlatformInfo.cpp:390

Scope (from outer to inner):

file
function     void FGenericDataDrivenShaderPlatformInfo::Initialize

Source code excerpt:

							if (GetFeatureLevelFromName(Item.PreviewFeatureLevelName, PreviewFeatureLevel))
							{
								PreviewInfo.MaxFeatureLevel = PreviewFeatureLevel;
							}

							PlatformNameToShaderPlatformMap.FindOrAdd(PreviewInfo.Name) = PreviewShaderPlatform;
						}
					}
				}

#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/DataDrivenShaderPlatformInfo.cpp:412

Scope (from outer to inner):

file
function     void FGenericDataDrivenShaderPlatformInfo::UpdatePreviewPlatforms

Source code excerpt:

		if (IsValid(PreviewPlatform) && GetIsPreviewPlatform(PreviewPlatform))
		{
			const ERHIFeatureLevel::Type PreviewFeatureLevel = Infos[PreviewPlatform].MaxFeatureLevel;
			const EShaderPlatform RuntimePlatform = GRHIGlobals.ShaderPlatformForFeatureLevel[PreviewFeatureLevel];

			if (RuntimePlatform < SP_NumPlatforms)
			{
				FGenericDataDrivenShaderPlatformInfo& PreviewInfo = Infos[PreviewPlatform];
				const FGenericDataDrivenShaderPlatformInfo& RuntimeInfo = Infos[RuntimePlatform];

#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/Windows/WindowsDynamicRHI.cpp:202

Scope (from outer to inner):

file
function     TOptional<ERHIFeatureLevel::Type> FParsedWindowsDynamicRHIConfig::GetHighestSupportedFeatureLevel

Source code excerpt:

	}

	ERHIFeatureLevel::Type MaxFeatureLevel = (ERHIFeatureLevel::Type)0;
	for (ERHIFeatureLevel::Type SupportedFeatureLevel : FeatureLevels)
	{
		MaxFeatureLevel = std::max(MaxFeatureLevel, SupportedFeatureLevel);
	}
	return MaxFeatureLevel;
}

TOptional<ERHIFeatureLevel::Type> FParsedWindowsDynamicRHIConfig::GetNextHighestTargetedFeatureLevel(EWindowsRHI InWindowsRHI, ERHIFeatureLevel::Type InFeatureLevel) const
{
	TArray<ERHIFeatureLevel::Type> LowerFeatureLevels(RHIConfigs[(int32)InWindowsRHI].FeatureLevels);
	LowerFeatureLevels.RemoveAll([InFeatureLevel](ERHIFeatureLevel::Type OtherFeatureLevel) { return OtherFeatureLevel >= InFeatureLevel; });

#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/Windows/WindowsDynamicRHI.cpp:217

Scope (from outer to inner):

file
function     TOptional<ERHIFeatureLevel::Type> FParsedWindowsDynamicRHIConfig::GetNextHighestTargetedFeatureLevel

Source code excerpt:

	if (LowerFeatureLevels.Num())
	{
		ERHIFeatureLevel::Type MaxFeatureLevel = (ERHIFeatureLevel::Type)0;
		for (ERHIFeatureLevel::Type SupportedFeatureLevel : LowerFeatureLevels)
		{
			MaxFeatureLevel = std::max(MaxFeatureLevel, SupportedFeatureLevel);
		}
		return MaxFeatureLevel;
	}

	return TOptional<ERHIFeatureLevel::Type>();
}

bool FParsedWindowsDynamicRHIConfig::IsFeatureLevelTargeted(EWindowsRHI InWindowsRHI, ERHIFeatureLevel::Type InFeatureLevel) const

#Loc: <Workspace>/Engine/Source/Runtime/RHI/Public/DataDrivenShaderPlatformInfo.h:20

Scope (from outer to inner):

file
class        class FGenericDataDrivenShaderPlatformInfo

Source code excerpt:

	FName Name;
	FName Language;
	ERHIFeatureLevel::Type MaxFeatureLevel;
	FName ShaderFormat;
	uint32 ShaderPropertiesHash;
	uint32 bIsMobile : 1;
	uint32 bIsMetalMRT : 1;
	uint32 bIsPC : 1;
	uint32 bIsConsole : 1;

#Loc: <Workspace>/Engine/Source/Runtime/RHI/Public/DataDrivenShaderPlatformInfo.h:197

Scope (from outer to inner):

file
class        class FGenericDataDrivenShaderPlatformInfo
function     static const ERHIFeatureLevel::Type GetMaxFeatureLevel

Source code excerpt:

	{
		check(IsValid(Platform));
		return Infos[Platform].MaxFeatureLevel;
	}

	static FORCEINLINE_DEBUGGABLE const bool GetIsMobile(const FStaticShaderPlatform Platform)
	{
		check(IsValid(Platform));
		return Infos[Platform].bIsMobile;

#Loc: <Workspace>/Engine/Source/Runtime/Windows/D3D11RHI/Private/Windows/WindowsD3D11Device.cpp:347

Scope: file

Source code excerpt:


/**
 * Attempts to create a D3D11 device for the adapter using at most MaxFeatureLevel.
 * If creation is successful, true is returned and the supported feature level is set in OutFeatureLevel.
 */
static bool SafeTestD3D11CreateDevice(IDXGIAdapter* Adapter,D3D_FEATURE_LEVEL MinFeatureLevel,D3D_FEATURE_LEVEL MaxFeatureLevel,D3D_FEATURE_LEVEL* OutFeatureLevel)
{
	ID3D11Device* D3DDevice = nullptr;
	ID3D11DeviceContext* D3DDeviceContext = nullptr;
	uint32 DeviceFlags = D3D11_CREATE_DEVICE_SINGLETHREADED;
	// Use a debug device if specified on the command line.
	if(GRHIGlobals.IsDebugLayerEnabled)

#Loc: <Workspace>/Engine/Source/Runtime/Windows/D3D11RHI/Private/Windows/WindowsD3D11Device.cpp:378

Scope (from outer to inner):

file
function     static bool SafeTestD3D11CreateDevice

Source code excerpt:

	while (FirstAllowedFeatureLevel < NumAllowedFeatureLevels)
	{
		if (RequestedFeatureLevels[FirstAllowedFeatureLevel] == MaxFeatureLevel)
		{
			break;
		}
		FirstAllowedFeatureLevel++;
	}

#Loc: <Workspace>/Engine/Source/Runtime/Windows/D3D11RHI/Private/Windows/WindowsD3D11Device.cpp:395

Scope (from outer to inner):

file
function     static bool SafeTestD3D11CreateDevice

Source code excerpt:

	
	NumAllowedFeatureLevels = LastAllowedFeatureLevel - FirstAllowedFeatureLevel + 1;
	if (MaxFeatureLevel < MinFeatureLevel || NumAllowedFeatureLevels <= 0)
	{
		return false;
	}

	__try
	{