Files
UnrealEngine/Engine/Source/Editor/DeviceProfileServices/Private/CheckAndroidDeviceProfileCommandlet.cpp
2025-05-18 13:04:45 +08:00

251 lines
10 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "CheckAndroidDeviceProfileCommandlet.h"
#include "Containers/Array.h"
#include "Containers/Map.h"
#include "DeviceProfiles/DeviceProfile.h"
#include "DeviceProfiles/DeviceProfileManager.h"
#include "DeviceProfiles/DeviceProfileMatching.h"
#include "Dom/JsonObject.h"
#include "GenericPlatform/GenericPlatformMemory.h"
#include "HAL/FileManager.h"
#include "HAL/PlatformCrt.h"
#include "IDeviceProfileSelectorModule.h"
#include "JsonObjectConverter.h"
#include "Logging/LogCategory.h"
#include "Logging/LogMacros.h"
#include "Misc/AssertionMacros.h"
#include "Misc/CString.h"
#include "Misc/ConfigCacheIni.h"
#include "Misc/FileHelper.h"
#include "Modules/ModuleManager.h"
#include "PIEPreviewDeviceSpecification.h"
#include "Serialization/JsonReader.h"
#include "Serialization/JsonSerializer.h"
#include "Templates/SharedPointer.h"
#include "Templates/Tuple.h"
#include "Trace/Detail/Channel.h"
#include "UObject/Class.h"
#include "UObject/NameTypes.h"
#include "UObject/UnrealNames.h"
DEFINE_LOG_CATEGORY_STATIC(LogCheckAndroidDeviceProfile, Log, All);
EPlatformMemorySizeBucket DetermineDeviceMemorySizeBucket(int32 TotalPhysicalMemoryGB)
{
EPlatformMemorySizeBucket Bucket = EPlatformMemorySizeBucket::Default;
static int32 LargestMemoryGB = 0, LargerMemoryGB = 0, DefaultMemoryGB = 0, SmallerMemoryGB = 0, SmallestMemoryGB = 0, TiniestMemoryGB = 0;
static bool bTriedPlatformBuckets = false;
if (!bTriedPlatformBuckets)
{
bTriedPlatformBuckets = true;
FConfigFile EngineConfigFile;
if (FConfigCacheIni::LoadLocalIniFile(EngineConfigFile, TEXT("Engine"), true, TEXT("Android")))
{
// get values for this platform from it's .ini
EngineConfigFile.GetInt(TEXT("PlatformMemoryBuckets"), TEXT("LargestMemoryBucket_MinGB"), LargestMemoryGB);
EngineConfigFile.GetInt(TEXT("PlatformMemoryBuckets"), TEXT("LargerMemoryBucket_MinGB"), LargerMemoryGB);
EngineConfigFile.GetInt(TEXT("PlatformMemoryBuckets"), TEXT("DefaultMemoryBucket_MinGB"), DefaultMemoryGB);
EngineConfigFile.GetInt(TEXT("PlatformMemoryBuckets"), TEXT("SmallerMemoryBucket_MinGB"), SmallerMemoryGB);
EngineConfigFile.GetInt(TEXT("PlatformMemoryBuckets"), TEXT("SmallestMemoryBucket_MinGB"), SmallestMemoryGB);
EngineConfigFile.GetInt(TEXT("PlatformMemoryBuckets"), TEXT("TiniestMemoryBucket_MinGB"), TiniestMemoryGB);
}
}
// if at least Smaller is specified, we can set the Bucket
if (SmallerMemoryGB > 0)
{
if (TotalPhysicalMemoryGB >= SmallerMemoryGB)
{
Bucket = EPlatformMemorySizeBucket::Smaller;
}
else if (TotalPhysicalMemoryGB >= SmallestMemoryGB)
{
Bucket = EPlatformMemorySizeBucket::Smallest;
}
else
{
Bucket = EPlatformMemorySizeBucket::Tiniest;
}
}
if (DefaultMemoryGB > 0 && TotalPhysicalMemoryGB >= DefaultMemoryGB)
{
Bucket = EPlatformMemorySizeBucket::Default;
}
if (LargerMemoryGB > 0 && TotalPhysicalMemoryGB >= LargerMemoryGB)
{
Bucket = EPlatformMemorySizeBucket::Larger;
}
if (LargestMemoryGB > 0 && TotalPhysicalMemoryGB >= LargestMemoryGB)
{
Bucket = EPlatformMemorySizeBucket::Largest;
}
return Bucket;
}
int32 UCheckAndroidDeviceProfileCommandlet::Main(const FString& RawCommandLine)
{
TArray<FString> Tokens;
TArray<FString> Switches;
TMap<FString, FString> Params;
ParseCommandLine(*RawCommandLine, Tokens, Switches, Params);
FString ParamDeviceSpecsFolder = Params.FindRef(TEXT("DeviceSpecsFolder"));
FString ParamDeviceSpecsFile = Params.FindRef(TEXT("DeviceSpecsFile"));
FString ForcedDeviceProfileName = Params.FindRef(TEXT("OverrideDP"));
FString OutputFolder = Params.FindRef(TEXT("OutDir"));
TArray<FString> DeviceSpecificationFileNames;
if (!ParamDeviceSpecsFolder.IsEmpty())
{
IFileManager::Get().FindFiles(DeviceSpecificationFileNames, *(ParamDeviceSpecsFolder / TEXT("*.json")), true, false);
}
else if (!ParamDeviceSpecsFile.IsEmpty())
{
DeviceSpecificationFileNames.Add(ParamDeviceSpecsFile);
}
FName DeviceProfileSelectorModule("AndroidDeviceProfileSelector");
IDeviceProfileSelectorModule* AndroidDeviceProfileSelector = FModuleManager::LoadModulePtr<IDeviceProfileSelectorModule>(DeviceProfileSelectorModule);
if (ensure(AndroidDeviceProfileSelector != nullptr))
{
do
{
TMap<FName, FString> DeviceParameters;
FString DeviceName;
FString OutputFilename;
if (DeviceSpecificationFileNames.Num())
{
FString DeviceSpecsFile = DeviceSpecificationFileNames.Pop();
int32 ExtensionPos;
if (DeviceSpecsFile.FindLastChar(TEXT('.'), ExtensionPos))
{
DeviceName = DeviceSpecsFile.Left(ExtensionPos);
OutputFilename = DeviceName;
}
FString JsonLocation = ParamDeviceSpecsFolder / DeviceSpecsFile;
AndroidDeviceProfileSelector->GetDeviceParametersFromJson(JsonLocation, DeviceParameters);
}
else
{
DeviceName = TEXT("[no name]");
DeviceParameters.Add(FName(TEXT("SRC_GPUFamily")), Params.FindRef(TEXT("GPUFamily")));
DeviceParameters.Add(FName(TEXT("SRC_GLVersion")), Params.FindRef(TEXT("GLVersion")));
DeviceParameters.Add(FName(TEXT("SRC_VulkanAvailable")), Params.FindRef(TEXT("VulkanAvailable")));
DeviceParameters.Add(FName(TEXT("SRC_VulkanVersion")), Params.FindRef(TEXT("VulkanVersion")));
DeviceParameters.Add(FName(TEXT("SRC_AndroidVersion")), Params.FindRef(TEXT("AndroidVersion")));
DeviceParameters.Add(FName(TEXT("SRC_DeviceMake")),
Tokens.Num() == 2 ? Tokens[0] :
Params.FindRef(TEXT("DeviceMake")));
DeviceParameters.Add(FName(TEXT("SRC_DeviceModel")),
Tokens.Num() == 1 ? Tokens[0] :
Tokens.Num() == 2 ? Tokens[1] :
Params.FindRef(TEXT("DeviceModel")));
DeviceParameters.Add(FName(TEXT("SRC_DeviceBuildNumber")), Params.FindRef(TEXT("DeviceBuildNumber")));
DeviceParameters.Add(FName(TEXT("SRC_UsingHoudini")), Params.FindRef(TEXT("UsingHoudini")));
DeviceParameters.Add(FName(TEXT("SRC_Hardware")), Params.FindRef(TEXT("Hardware")));
DeviceParameters.Add(FName(TEXT("SRC_Chipset")), Params.FindRef(TEXT("Chipset")));
DeviceParameters.Add(FName(TEXT("SRC_TotalPhysicalGB")), Params.FindRef(TEXT("TotalPhysicalGB")));
DeviceParameters.Add(FName(TEXT("SRC_HMDSystemName")), TEXT(""));
DeviceParameters.Add(FName(TEXT("SRC_SM5Available")), Params.FindRef(TEXT("SM5Available")));
DeviceParameters.Add(FName(TEXT("SRC_ResolutionX")), Params.FindRef(TEXT("ResolutionX")));
DeviceParameters.Add(FName(TEXT("SRC_ResolutionY")), Params.FindRef(TEXT("ResolutionY")));
DeviceParameters.Add(FName(TEXT("SRC_InsetsLeft")), Params.FindRef(TEXT("InsetsLeft")));
DeviceParameters.Add(FName(TEXT("SRC_InsetsTop")), Params.FindRef(TEXT("InsetsTop")));
DeviceParameters.Add(FName(TEXT("SRC_InsetsRight")), Params.FindRef(TEXT("InsetsRight")));
DeviceParameters.Add(FName(TEXT("SRC_InsetsBottom")), Params.FindRef(TEXT("InsetsBottom")));
}
AndroidDeviceProfileSelector->SetSelectorProperties(DeviceParameters);
FString ProfileName = ForcedDeviceProfileName.IsEmpty() ? AndroidDeviceProfileSelector->GetDeviceProfileName() : ForcedDeviceProfileName;
TArray<FSelectedFragmentProperties> SelectedFragments;
UE_LOG(LogCheckAndroidDeviceProfile, Display, TEXT("%s Selected Device Profile: %s"), *DeviceName, *ProfileName);
int32 TotalPhysGB = FCString::Atoi(*DeviceParameters.FindChecked(TEXT("SRC_TotalPhysicalGB")));
EPlatformMemorySizeBucket MemorySizeBucket = DetermineDeviceMemorySizeBucket(TotalPhysGB);
FString PlatformOverride(TEXT("Android"));
FString ProfileDescription;
UDeviceProfile* Profile = UDeviceProfileManager::Get().FindProfile(ProfileName, false);
TArray<FString> CVars;
if (!Profile)
{
UE_LOG(LogCheckAndroidDeviceProfile, Error, TEXT("Failed to find requested device profile. %s requested Device Profile: %s But could not be found!"), *DeviceName, *ProfileName);
}
else
{
// Set the memory size bucket for this device.
Profile->SetPreviewMemorySizeBucket(MemorySizeBucket);
// ensure any previous expanded cvars are cleared out.
Profile->ClearAllExpandedCVars();
// get all GetAllExpandedCVars re-runs the DP selection.
TMap<FString, FString> CVarMap = Profile->GetAllExpandedCVars();
for (auto CVarIt : CVarMap)
{
CVars.Add(FString::Printf(TEXT("%s=%s"), *CVarIt.Key, *CVarIt.Value));
}
SelectedFragments = Profile->SelectedFragments;
}
if (!OutputFilename.IsEmpty())
{
FString output;
if (!DeviceName.IsEmpty())
{
output += FString::Printf(TEXT("Device name : %s\n\n"), *DeviceName);
}
if (!Profile)
{
output += FString::Printf(TEXT("Failed to find device profile : %s\n\n"), *ProfileName);
}
OutputFilename = DeviceName + TEXT("_") + DeviceParameters.FindChecked(TEXT("SRC_GPUFamily")) + TEXT("_") + DeviceParameters.FindChecked(TEXT("SRC_TotalPhysicalGB")) + TEXT("GB.txt");
output += FString::Printf(TEXT("AndroidDeviceProfileSelector Params:\n"));
TArray<FName> SortedKeys;
DeviceParameters.GenerateKeyArray(SortedKeys);
//SortedKeys.Sort();
for (FName& ParamKey : SortedKeys)
{
output += FString::Printf(TEXT("[%s]=%s\n"), *ParamKey.ToString(), *DeviceParameters.FindChecked(ParamKey));
}
output += FString::Printf(TEXT("\nDevice Mem Bucket: %s\n"), LexToString(MemorySizeBucket));
output += FString::Printf(TEXT("\nSelected fragments :\n%s"), SelectedFragments.Num() == 0 ? TEXT("-none-\n") : TEXT(""));
for (FSelectedFragmentProperties& Fragment : SelectedFragments)
{
FString FragTag;
if (Fragment.Tag != NAME_None)
{
FragTag = TEXT("[") + Fragment.Tag.ToString() + TEXT("]");
}
output += FString::Printf(TEXT("%s%s : Enabled=%s\n"), *FragTag, *Fragment.Fragment, Fragment.bEnabled ? TEXT("true") : TEXT("false"));
}
output += FString::Printf(TEXT("\n\nSelected device Profile: %s\nSelected device profile description: %s\n"), *ProfileName, *ProfileDescription);
// may not want this:
const bool bSortCVars = true;
if (bSortCVars)
{
output += FString::Printf(TEXT("Sorted "));
CVars.Sort();
}
FString CVarsOnly = FString::Printf(TEXT("CVars:\n"));
for (FString& CVar : CVars)
{
CVarsOnly += FString::Printf(TEXT("%s\n"), *CVar);
}
output += CVarsOnly;
FFileHelper::SaveStringToFile(output, *(OutputFolder / OutputFilename));
FFileHelper::SaveStringToFile(CVarsOnly, *(OutputFolder / TEXT("CVarsOnly") / OutputFilename));
}
} while (DeviceSpecificationFileNames.Num());
}
return 0;
}