Device Profile inheritance confusion

It seems that if I have an empty Windows custom profile that inherits from base custom profile, other unrelated windows profiles stomp their cvars over the base. That seems really weird! Am I doing something wrong here or how is this inheritance supposed to work?

I want to keep all ProfileA things away from ProfileB, but seems like having specific platform variants cause them to leak together somehow?

Eg.

In Config/DefaultDeviceProfiles.ini add:

[DeviceProfiles]

+DeviceProfileNameAndTypes=ProfileA

[ProfileA DeviceProfile]

DeviceType=Windows

; === Set all quality to High (2) ===

; WindowsEditor will override these to Cine (4) for maximum editor quality

+CVars=sg.ViewDistanceQuality=3

then in Config/Custom/ProfileB/DefaultDeviceProfiles.ini

Add

[DeviceProfiles]

+DeviceProfileNameAndTypes=ProfileB,Windows

[Windows DeviceProfile]

BaseProfileName=ProfileB

; nothing here, shouldn’t need anything because won’t I inherit from ProfileB?

[ProfileB DeviceProfile]

DeviceType=Windows

+CVars=sg.ViewDistanceQuality=4

I would expect that on building a packaged build and passing in:

-AdditionalCookerOptions=-CustomConfig=ProfileB

That on windows I would only get the values for ProfileB, but this is not what occurs.

Instead of seeing ViewDistanceQuality=4, I see 3. It seems like, looking at the logs, as there is nothing under ProfileB Windows, it is bringing in cvars from ProfileA Windows.

This seems really weird! I would expect Profile B Windows to be populated with its base cvars.

The solution here seems to be either commenting out all Windows specific device platforms or copying the ProfileB stuff from base to windows. (so what’s the point of inheritance??)

Surely I’m doing something wrong here because the inheritance doesn’t seem to work and doesn’t seem useful if Profile A things can be brought into Profile B.

[Attachment Removed]

Steps to Reproduce

In Config/DefaultDeviceProfiles.ini add:

[DeviceProfiles]

+DeviceProfileNameAndTypes=ProfileA

[ProfileADeviceProfile]

DeviceType=Windows

; === Set all quality to High (2) ===

; WindowsEditor will override these to Cine (4) for maximum editor quality

+CVars=sg.ViewDistanceQuality=3

then in Config/Custom/ProfileB/DefaultDeviceProfiles.ini

Add

[DeviceProfiles]

+DeviceProfileNameAndTypes=ProfileB,Windows

[Windows DeviceProfile]

BaseProfileName=ProfileB

; nothing here

[ProfileB DeviceProfile]

DeviceType=Windows

+CVars=sg.ViewDistanceQuality=4

I would expect that on building a packaged build and passing in:

-AdditionalCookerOptions=-CustomConfig=ProfileB

That on windows I would only get the values for ProfileB, but this is not what occurs.

Instead of seeing ViewDistanceQuality=4, I see 3. It seems like as there is nothing under ProfileB Windows, it is bringing in cvars from ProfileA Windows.

[Attachment Removed]

Hi,

I’m not sure the command line argument will work in a packaged build, do you see different results if you specify the CustomConfig file in your Target.cs file? That might not be helpful if you’re looking to set the profile at launch, but it’ll help narrow down the issue. The other possibility is that something further down the config hierarchy is clobbering the values, here’s the order things are processed from top to bottom (so later values will override earlier ones):

inline FConfigLayer GConfigLayers[] =
{
	/**************************************************
	**** CRITICAL NOTES
	**** If you change this array, you need to also change EnumerateConfigFileLocations() in ConfigHierarchy.cs!!!
	**** And maybe UObject::GetDefaultConfigFilename(), UObject::GetGlobalUserConfigFilename()
	**************************************************/
 
	// Engine/Base.ini
	{ TEXT("AbsoluteBase"),				TEXT("{ENGINE}/Config/Base.ini"), EConfigLayerFlags::NoExpand},
 
	// Engine/Base*.ini
	{ TEXT("Base"),						TEXT("{ENGINE}/Config/Base{TYPE}.ini"), EConfigLayerFlags::UseGlobalConfigCache },
	// Engine/Platform/BasePlatform*.ini
	{ TEXT("BasePlatform"),				TEXT("{ENGINE}/Config/{PLATFORM}/Base{PLATFORM}{TYPE}.ini"), EConfigLayerFlags::UseGlobalConfigCache  },
	// Project/Default*.ini
	{ TEXT("ProjectDefault"),			TEXT("{PROJECT}/Config/Default{TYPE}.ini"), EConfigLayerFlags::AllowCommandLineOverride | EConfigLayerFlags::UseGlobalConfigCache },
	// Project/Generated*.ini Reserved for files generated by build process and should never be checked in 
	{ TEXT("ProjectGenerated"),			TEXT("{PROJECT}/Config/Generated{TYPE}.ini"), EConfigLayerFlags::UseGlobalConfigCache },
	// Project/Custom/CustomConfig/Default*.ini only if CustomConfig is defined
	{ TEXT("CustomConfig"),				TEXT("{PROJECT}/Config/Custom/{CUSTOMCONFIG}/Default{TYPE}.ini"), EConfigLayerFlags::RequiresCustomConfig | EConfigLayerFlags::UseGlobalConfigCache },
	// Engine/Platform/Platform*.ini
	{ TEXT("EnginePlatform"),			TEXT("{ENGINE}/Config/{PLATFORM}/{PLATFORM}{TYPE}.ini"), EConfigLayerFlags::UseGlobalConfigCache },
	// Project/Platform/Platform*.ini
	{ TEXT("ProjectPlatform"),			TEXT("{PROJECT}/Config/{PLATFORM}/{PLATFORM}{TYPE}.ini"), EConfigLayerFlags::UseGlobalConfigCache },
	// Project/Platform/GeneratedPlatform*.ini Reserved for files generated by build process and should never be checked in 
	{ TEXT("ProjectPlatformGenerated"),	TEXT("{PROJECT}/Config/{PLATFORM}/Generated{PLATFORM}{TYPE}.ini"), EConfigLayerFlags::UseGlobalConfigCache },
	// Project/Platform/Custom/CustomConfig/Platform*.ini only if CustomConfig is defined
	{ TEXT("CustomConfigPlatform"),		TEXT("{PROJECT}/Config/{PLATFORM}/Custom/{CUSTOMCONFIG}/{PLATFORM}{TYPE}.ini"), EConfigLayerFlags::RequiresCustomConfig| EConfigLayerFlags::UseGlobalConfigCache },
	// AppSettings/.../System*.ini
	{ TEXT("AppSettingsDir"),			TEXT("{APPSETTINGS}Unreal Engine/Engine/Config/System{TYPE}.ini"), EConfigLayerFlags::NoExpand },
	// UserSettings/.../User*.ini
	{ TEXT("UserSettingsDir"),			TEXT("{USERSETTINGS}Unreal Engine/Engine/Config/User{TYPE}.ini"), EConfigLayerFlags::NoExpand },
	// UserDir/.../User*.ini
	{ TEXT("UserDir"),					TEXT("{USER}Unreal Engine/Engine/Config/User{TYPE}.ini"), EConfigLayerFlags::NoExpand },
	// Project/User*.ini
	{ TEXT("GameDirUser"),				TEXT("{PROJECT}/Config/User{TYPE}.ini"), EConfigLayerFlags::NoExpand },
};

Assuming both of your device profile configs are at the project level I don’t think there should be any issues here, so the final collated config (assuming the CustomConfig is actually being picked up) should have everything.

For what it’s worth, custom configs are a bit of a hack; the preference here is usually to keep all of the device profiles in one place (Config/DefaultDeviceProfiles.ini) and switch between them at runtime. We also don’t typically make multiple profiles for desktop platforms since there are countless hardware permutations. Instead, we’ll either auto-detect (see ULyraSettingsLocal::RunAutoBenchmark for an example) or expose settings for adjusting scalability groups manually.

Best,

Cody

[Attachment Removed]