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:
- The value of MaxFeatureLevel affects which rendering features are available in the engine.
- It’s platform-specific and can vary between different hardware configurations.
- It’s used to determine compatibility with certain shaders and rendering techniques.
Best practices when using this variable include:
- Always check the MaxFeatureLevel before attempting to use high-end rendering features.
- Design your rendering pipeline to gracefully degrade on lower feature levels.
- Use the DataDrivenShaderPlatformInfo system to handle platform-specific rendering capabilities.
- 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
{