Files
UnrealEngineUWP/Engine/Source/Editor/MaterialEditor/Private/MaterialStatsCommon.cpp

650 lines
26 KiB
C++
Raw Normal View History

// Copyright Epic Games, Inc. All Rights Reserved.
//
#include "MaterialStatsCommon.h"
#include "EngineGlobals.h"
#include "MaterialStats.h"
#include "LocalVertexFactory.h"
#include "GPUSkinVertexFactory.h"
#include "MaterialEditorSettings.h"
#include "RHIShaderFormatDefinitions.inl"
#include "ShaderCompilerCore.h"
#include "Styling/StyleColors.h"
/***********************************************************************************************************************/
/*begin FMaterialResourceStats functions*/
void FMaterialResourceStats::SetupExtaCompilationSettings(const EShaderPlatform Platform, FExtraShaderCompilerSettings& Settings) const
{
Settings.bExtractShaderSource = true;
Settings.OfflineCompilerPath = FMaterialStatsUtils::GetPlatformOfflineCompilerPath(Platform);
}
/*end FMaterialResourceStats functions*/
/***********************************************************************************************************************/
/***********************************************************************************************************************/
/*begin FMaterialStatsUtils */
TSharedPtr<FMaterialStats> FMaterialStatsUtils::CreateMaterialStats(class IMaterialEditor* MaterialEditor)
{
TSharedPtr<FMaterialStats> MaterialStats = MakeShareable(new FMaterialStats());
MaterialStats->Initialize(MaterialEditor);
return MaterialStats;
}
FString FMaterialStatsUtils::MaterialQualityToString(const EMaterialQualityLevel::Type Quality)
{
FString StrQuality;
switch (Quality)
{
case EMaterialQualityLevel::High:
StrQuality = TEXT("High Quality");
break;
case EMaterialQualityLevel::Medium:
StrQuality = TEXT("Medium Quality");
break;
case EMaterialQualityLevel::Low:
StrQuality = TEXT("Low Quality");
break;
case EMaterialQualityLevel::Epic:
StrQuality = TEXT("Epic Quality");
break;
}
return StrQuality;
}
FString FMaterialStatsUtils::MaterialQualityToShortString(const EMaterialQualityLevel::Type Quality)
{
FString StrQuality;
switch (Quality)
{
case EMaterialQualityLevel::High:
StrQuality = TEXT("High");
break;
case EMaterialQualityLevel::Medium:
StrQuality = TEXT("Medium");
break;
case EMaterialQualityLevel::Low:
StrQuality = TEXT("Low");
break;
case EMaterialQualityLevel::Epic:
StrQuality = TEXT("Epic");
break;
}
return StrQuality;
}
EMaterialQualityLevel::Type FMaterialStatsUtils::StringToMaterialQuality(const FString& StrQuality)
{
if (StrQuality.Equals(TEXT("High Quality")))
{
return EMaterialQualityLevel::High;
}
else if (StrQuality.Equals(TEXT("Medium Quality")))
{
return EMaterialQualityLevel::Medium;
}
else if (StrQuality.Equals(TEXT("Low Quality")))
{
return EMaterialQualityLevel::Low;
}
else if (StrQuality.Equals(TEXT("Epic Quality")))
{
return EMaterialQualityLevel::Epic;
}
return EMaterialQualityLevel::Num;
}
FString FMaterialStatsUtils::GetPlatformTypeName(const EPlatformCategoryType InEnumValue)
{
FString PlatformName;
switch (InEnumValue)
{
case EPlatformCategoryType::Desktop:
PlatformName = FString("Desktop");
break;
case EPlatformCategoryType::Android:
PlatformName = FString("Android");
break;
case EPlatformCategoryType::IOS:
PlatformName = FString("IOS");
break;
case EPlatformCategoryType::Console:
PlatformName = FString("Console");
break;
}
return PlatformName;
}
FString FMaterialStatsUtils::ShaderPlatformTypeName(const EShaderPlatform PlatformID)
{
FString FormatName = LexToString(PlatformID);
if (FormatName.StartsWith(TEXT("SF_")))
{
FormatName.MidInline(3, MAX_int32, false);
}
return FormatName;
}
FString FMaterialStatsUtils::GetPlatformOfflineCompilerPath(const EShaderPlatform ShaderPlatform)
{
if (FDataDrivenShaderPlatformInfo::GetNeedsOfflineCompiler(ShaderPlatform))
{
if (FDataDrivenShaderPlatformInfo::GetIsAndroidOpenGLES(ShaderPlatform)
|| (FDataDrivenShaderPlatformInfo::GetIsLanguageVulkan(ShaderPlatform) && FDataDrivenShaderPlatformInfo::GetIsMobile(ShaderPlatform)))
{
return FPaths::ConvertRelativePathToFull(GetDefault<UMaterialEditorSettings>()->MaliOfflineCompilerPath.FilePath);
}
}
return FString();
}
bool FMaterialStatsUtils::IsPlatformOfflineCompilerAvailable(const EShaderPlatform ShaderPlatform)
{
FString CompilerPath = GetPlatformOfflineCompilerPath(ShaderPlatform);
bool bCompilerExists = FPaths::FileExists(CompilerPath);
return bCompilerExists;
}
bool FMaterialStatsUtils::PlatformNeedsOfflineCompiler(const EShaderPlatform ShaderPlatform)
{
return FDataDrivenShaderPlatformInfo::GetNeedsOfflineCompiler(ShaderPlatform);
}
FString FMaterialStatsUtils::RepresentativeShaderTypeToString(const ERepresentativeShader ShaderType)
{
switch (ShaderType)
{
case ERepresentativeShader::StationarySurface:
return TEXT("Stationary surface");
break;
case ERepresentativeShader::StationarySurfaceCSM:
return TEXT("Stationary surface + CSM");
break;
case ERepresentativeShader::StationarySurfaceNPointLights:
return TEXT("Stationary surface + Point Lights");
break;
case ERepresentativeShader::DynamicallyLitObject:
return TEXT("Dynamically lit object");
break;
case ERepresentativeShader::StaticMesh:
return TEXT("Static Mesh");
break;
case ERepresentativeShader::SkeletalMesh:
return TEXT("Skeletal Mesh");
break;
case ERepresentativeShader::UIDefaultFragmentShader:
return TEXT("UI Pixel Shader");
break;
case ERepresentativeShader::UIDefaultVertexShader:
return TEXT("UI Vertex Shader");
break;
case ERepresentativeShader::UIInstancedVertexShader:
return TEXT("UI Instanced Vertex Shader");
break;
default:
return TEXT("Unknown shader name");
break;
}
}
FSlateColor FMaterialStatsUtils::PlatformTypeColor(EPlatformCategoryType PlatformType)
{
FSlateColor Color(FStyleColors::Foreground);
switch (PlatformType)
{
case EPlatformCategoryType::Desktop:
Color = FStyleColors::AccentBlue;
break;
case EPlatformCategoryType::Android:
Color = FStyleColors::AccentGreen;
break;
case EPlatformCategoryType::IOS:
Color = FStyleColors::AccentYellow;
break;
case EPlatformCategoryType::Console:
Color = FStyleColors::AccentPurple;
break;
default:
return Color;
break;
}
return Color;
}
FSlateColor FMaterialStatsUtils::QualitySettingColor(const EMaterialQualityLevel::Type QualityType)
{
switch (QualityType)
{
case EMaterialQualityLevel::Low:
return FStyleColors::AccentGreen;
break;
case EMaterialQualityLevel::High:
return FStyleColors::AccentOrange;
break;
case EMaterialQualityLevel::Medium:
return FStyleColors::Warning;
break;
case EMaterialQualityLevel::Epic:
return FStyleColors::Error;
break;
default:
return FStyleColors::Foreground;
break;
}
return FStyleColors::Foreground;
}
static void MobileBasePassShaderName(bool bVertexShader, const TCHAR* PolicyName, bool bEnableLocalLights, bool bHDR, bool bSkyLight, FString& OutName)
{
OutName.Reset();
OutName.Append(bVertexShader ? TEXT("TMobileBasePassVS") : TEXT("TMobileBasePassPS"));
OutName.Append(PolicyName);
OutName.Append(bHDR ? TEXT("HDRLinear64") : TEXT("LDRGamma32"));
if (!bVertexShader && bSkyLight)
{
OutName.Append(TEXT("SkyLight"));
}
if (!bVertexShader && bEnableLocalLights)
{
OutName.Append(TEXT("EnableLocalLights"));
}
}
void FMaterialStatsUtils::GetRepresentativeShaderTypesAndDescriptions(TMap<FName, TArray<FRepresentativeShaderInfo>>& ShaderTypeNamesAndDescriptions, const FMaterial* TargetMaterial)
{
static auto* MobileHDR = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.MobileHDR"));
bool bMobileHDR = MobileHDR && MobileHDR->GetValueOnAnyThread() == 1;
static const FName FLocalVertexFactoryName = FLocalVertexFactory::StaticType.GetFName();
static const FName FGPUFactoryName = TEXT("TGPUSkinVertexFactoryDefault");
if (TargetMaterial->IsUIMaterial())
{
static FName TSlateMaterialShaderPSDefaultName = TEXT("TSlateMaterialShaderPSDefault");
ShaderTypeNamesAndDescriptions.FindOrAdd(FLocalVertexFactoryName)
.Add(FRepresentativeShaderInfo(ERepresentativeShader::UIDefaultFragmentShader, TSlateMaterialShaderPSDefaultName, TEXT("Default UI Pixel Shader")));
static FName TSlateMaterialShaderVSfalseName = TEXT("TSlateMaterialShaderVSfalse");
ShaderTypeNamesAndDescriptions.FindOrAdd(FLocalVertexFactoryName)
.Add(FRepresentativeShaderInfo(ERepresentativeShader::UIDefaultVertexShader, TSlateMaterialShaderVSfalseName, TEXT("Default UI Vertex Shader")));
static FName TSlateMaterialShaderVStrueName = TEXT("TSlateMaterialShaderVStrue");
ShaderTypeNamesAndDescriptions.FindOrAdd(FLocalVertexFactoryName)
.Add(FRepresentativeShaderInfo(ERepresentativeShader::UIInstancedVertexShader, TSlateMaterialShaderVStrueName, TEXT("Instanced UI Vertex Shader")));
}
else if (TargetMaterial->GetFeatureLevel() >= ERHIFeatureLevel::SM5)
{
if (TargetMaterial->GetShadingModels().IsUnlit())
{
//unlit materials are never lightmapped
static FName TBasePassPSFNoLightMapPolicyName = TEXT("TBasePassPSFNoLightMapPolicy");
ShaderTypeNamesAndDescriptions.FindOrAdd(FLocalVertexFactoryName)
.Add(FRepresentativeShaderInfo(ERepresentativeShader::StationarySurface, TBasePassPSFNoLightMapPolicyName, TEXT("Base pass shader without light map")));
}
else
{
//also show a dynamically lit shader
static FName TBasePassPSFNoLightMapPolicyName = TEXT("TBasePassPSFNoLightMapPolicy");
ShaderTypeNamesAndDescriptions.FindOrAdd(FLocalVertexFactoryName)
.Add(FRepresentativeShaderInfo(ERepresentativeShader::DynamicallyLitObject, TBasePassPSFNoLightMapPolicyName, TEXT("Base pass shader")));
static auto* CVarAllowStaticLighting = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.AllowStaticLighting"));
const bool bAllowStaticLighting = CVarAllowStaticLighting->GetValueOnAnyThread() != 0;
if (bAllowStaticLighting)
{
if (TargetMaterial->IsUsedWithStaticLighting())
{
static FName TBasePassPSTLightMapPolicyName = TEXT("TBasePassPSTDistanceFieldShadowsAndLightMapPolicyHQ");
ShaderTypeNamesAndDescriptions.FindOrAdd(FLocalVertexFactoryName)
.Add(FRepresentativeShaderInfo(ERepresentativeShader::StationarySurface, TBasePassPSTLightMapPolicyName, TEXT("Base pass shader with Surface Lightmap")));
}
static FName TBasePassPSFPrecomputedVolumetricLightmapLightingPolicyName = TEXT("TBasePassPSFPrecomputedVolumetricLightmapLightingPolicy");
ShaderTypeNamesAndDescriptions.FindOrAdd(FLocalVertexFactoryName)
.Add(FRepresentativeShaderInfo(ERepresentativeShader::DynamicallyLitObject, TBasePassPSFPrecomputedVolumetricLightmapLightingPolicyName, TEXT("Base pass shader with Volumetric Lightmap")));
}
}
static FName TBasePassVSFNoLightMapPolicyName = TEXT("TBasePassVSFNoLightMapPolicy");
ShaderTypeNamesAndDescriptions.FindOrAdd(FLocalVertexFactoryName)
.Add(FRepresentativeShaderInfo(ERepresentativeShader::StaticMesh, TBasePassVSFNoLightMapPolicyName, TEXT("Base pass vertex shader")));
ShaderTypeNamesAndDescriptions.FindOrAdd(FGPUFactoryName)
.Add(FRepresentativeShaderInfo(ERepresentativeShader::SkeletalMesh, TBasePassVSFNoLightMapPolicyName, TEXT("Base pass vertex shader")));
Only compile the shaders needed to gather shader platform stats in the Material Editor. # Results Modfiying WorldGridMaterial with two platforms open in platform stats. - We compile a fixed number of shaders (less than 10 per platform) now instead of the 1078 shaders (per platform) w/ WorldGridMaterial. - On average ProcessCompiledShaderMaps is 40x faster. (1727ms vs. 43ms) - In the worst cast ProcessCompiledShaderMaps is 10.9x faster. (4865ms vs 445ms) - The material editor in this scenario goes from unusable to useable. # Changes - Add `FMaterial::CacheGivenTypes` to compile just the shader types given to it. - Call `GetRepresentativeShaderTypesAndDescriptions` to gather the shader types we care about and only submit jobs to compile those shaders when generating platform stats. - Since we are no longer compile a complete shader map the ShaderCount is incorrect. Now we call `GetShaderTypes` of the `FMaterialResource` to gather the number of shaders in the material. This function doesn't trigger shader compilation which is important. - Adding const to the following functions: - FMaterial::GetShaderTypesForLayout - FMaterial::GetShaderTypes - FMaterial::GetShaderTypes is now ENGINE_API so we can call it from the Material Editor. - Add `TBasePassPSFCachedVolumeIndirectLightingPolicy` shader type to FMaterialStatsUtils::GetRepresentativeShaderTypesAndDescriptions. This shader has the worst case sampler count. This ensures we compile this shader and are able to query the worst case sampler count for the platform stats. This is very ad-hoc, and could be improved in the future. #rb Ben.Ingram #jira UE-138623 #preflight 623b4e4cc3399da9533282cc [CL 19481265 by Jason Nadro in ue5-main branch]
2022-03-23 13:03:01 -04:00
// Add the shader type with the most sampler usages so we can accurately report the worst case scenario.
// This is ad-hoc, and ideally we have a better way for finding this shader type in the future.
ShaderTypeNamesAndDescriptions.FindOrAdd(FLocalVertexFactoryName)
.Add(FRepresentativeShaderInfo(ERepresentativeShader::StationarySurface, FName(TEXT("TBasePassPSFCachedVolumeIndirectLightingPolicy")), TEXT("MaxSampler")));
}
else
{
const TCHAR* DescSuffix = bMobileHDR ? TEXT(" (HDR)") : TEXT(" (LDR)");
FString ShaderNameStr;
if (TargetMaterial->GetShadingModels().IsUnlit())
{
bool bEnableLocalLights = false;
//unlit materials are never lightmapped
MobileBasePassShaderName(false, TEXT("FNoLightMapPolicy"), bEnableLocalLights, bMobileHDR, false, ShaderNameStr);
const FString Description = FString::Printf(TEXT("Mobile base pass shader without light map%s"), DescSuffix);
ShaderTypeNamesAndDescriptions.Add(FLocalVertexFactoryName)
.Add(FRepresentativeShaderInfo(ERepresentativeShader::StationarySurface, FName(ShaderNameStr), Description));
MobileBasePassShaderName(true, TEXT("FNoLightMapPolicy"), bEnableLocalLights, bMobileHDR, false, ShaderNameStr);
ShaderTypeNamesAndDescriptions.FindOrAdd(FLocalVertexFactoryName)
.Add(FRepresentativeShaderInfo(ERepresentativeShader::StaticMesh, FName(ShaderNameStr),
FString::Printf(TEXT("Mobile base pass vertex shader%s"), DescSuffix)));
ShaderTypeNamesAndDescriptions.FindOrAdd(FGPUFactoryName)
.Add(FRepresentativeShaderInfo(ERepresentativeShader::SkeletalMesh, FName(ShaderNameStr),
FString::Printf(TEXT("Mobile base pass vertex shader%s"), DescSuffix)));
}
else
{
static auto* CVarAllowStaticLighting = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.AllowStaticLighting"));
const bool bAllowStaticLighting = CVarAllowStaticLighting->GetValueOnAnyThread() != 0;
static auto* CVarMobileSkyLightPermutation = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.Mobile.SkyLightPermutation"));
const bool bOnlySkyPermutation = CVarMobileSkyLightPermutation->GetValueOnAnyThread() == 2;
if (bAllowStaticLighting && TargetMaterial->IsUsedWithStaticLighting())
{
static auto* CVarAllowDistanceFieldShadows = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.Mobile.AllowDistanceFieldShadows"));
const bool bAllowDistanceFieldShadows = CVarAllowDistanceFieldShadows->GetValueOnAnyThread() != 0;
if (bAllowDistanceFieldShadows)// distance field shadows
{
// distance field shadows only shaders
{
bool bEnableLocalLights = false;
MobileBasePassShaderName(false, TEXT("FMobileDistanceFieldShadowsAndLQLightMapPolicy"), bEnableLocalLights, bMobileHDR, bOnlySkyPermutation, ShaderNameStr);
const FString Description = FString::Printf(TEXT("Mobile base pass shader with distance field shadows%s"), DescSuffix);
ShaderTypeNamesAndDescriptions.FindOrAdd(FLocalVertexFactoryName)
.Add(FRepresentativeShaderInfo(ERepresentativeShader::StationarySurface, FName(ShaderNameStr), Description));
}
static auto* CVarAllowDistanceFieldShadowsAndCSM = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.Mobile.EnableStaticAndCSMShadowReceivers"));
const bool bAllowDistanceFieldShadowsAndCSM = CVarAllowDistanceFieldShadowsAndCSM->GetValueOnAnyThread() != 0;
if (bAllowDistanceFieldShadowsAndCSM)
{
// distance field shadows & CSM shaders
{
bool bEnableLocalLights = false;
MobileBasePassShaderName(false, TEXT("FMobileDistanceFieldShadowsLightMapAndCSMLightingPolicy"), bEnableLocalLights, bMobileHDR, bOnlySkyPermutation, ShaderNameStr);
const FString Description = FString::Printf(TEXT("Mobile base pass shader with distance field shadows and CSM%s"), DescSuffix);
ShaderTypeNamesAndDescriptions.FindOrAdd(FLocalVertexFactoryName)
.Add(FRepresentativeShaderInfo(ERepresentativeShader::StationarySurfaceCSM, FName(ShaderNameStr), Description));
}
{
bool bEnableLocalLights = true;
MobileBasePassShaderName(false, TEXT("FMobileDistanceFieldShadowsAndLQLightMapPolicy"), bEnableLocalLights, bMobileHDR, bOnlySkyPermutation, ShaderNameStr);
const FString Description = FString::Printf(TEXT("Mobile base pass shader with distance field shadows, CSM and local light(s) %s"), DescSuffix);
FRepresentativeShaderInfo ShaderInfo = FRepresentativeShaderInfo(ERepresentativeShader::StationarySurfaceNPointLights, FName(ShaderNameStr), Description);
ShaderTypeNamesAndDescriptions.FindOrAdd(FLocalVertexFactoryName).Add(ShaderInfo);
}
}
}
else //no shadows & lightmapped
{
{
bool bEnableLocalLights = false;
MobileBasePassShaderName(false, TEXT("TLightMapPolicyLQ"), bEnableLocalLights, bMobileHDR, bOnlySkyPermutation, ShaderNameStr);
ShaderTypeNamesAndDescriptions.FindOrAdd(FLocalVertexFactoryName)
.Add(FRepresentativeShaderInfo(ERepresentativeShader::StationarySurface, FName(ShaderNameStr),
FString::Printf(TEXT("Mobile base pass shader with static lighting%s"), DescSuffix)));
}
{
bool bEnableLocalLights = true;
MobileBasePassShaderName(false, TEXT("TLightMapPolicyLQ"), bEnableLocalLights, bMobileHDR, bOnlySkyPermutation, ShaderNameStr);
const FString Description = FString::Printf(TEXT("Mobile base pass shader with static lighting and local light(s) %s"), DescSuffix);
FRepresentativeShaderInfo ShaderInfo = FRepresentativeShaderInfo(ERepresentativeShader::StationarySurfaceNPointLights, FName(ShaderNameStr), Description);
ShaderTypeNamesAndDescriptions.FindOrAdd(FLocalVertexFactoryName).Add(ShaderInfo);
}
}
}
// only one of these 2 shader types will be displayed
// dynamically lit shader NoLightmapPolicy
bool bEnableLocalLights = false;
MobileBasePassShaderName(false, TEXT("FNoLightmapPolicy"), bEnableLocalLights, bMobileHDR, bOnlySkyPermutation, ShaderNameStr);
ShaderTypeNamesAndDescriptions.FindOrAdd(FLocalVertexFactoryName)
.Add(FRepresentativeShaderInfo(ERepresentativeShader::DynamicallyLitObject, FName(ShaderNameStr),
FString::Printf(TEXT("Mobile base pass shader with only dynamic lighting%s"), DescSuffix)));
MobileBasePassShaderName(true, TEXT("FNoLightMapPolicy"), bEnableLocalLights, bMobileHDR, bOnlySkyPermutation, ShaderNameStr);
ShaderTypeNamesAndDescriptions.FindOrAdd(FLocalVertexFactoryName)
.Add(FRepresentativeShaderInfo(ERepresentativeShader::StaticMesh, FName(ShaderNameStr),
FString::Printf(TEXT("Mobile base pass vertex shader%s"), DescSuffix)));
ShaderTypeNamesAndDescriptions.FindOrAdd(FGPUFactoryName)
.Add(FRepresentativeShaderInfo(ERepresentativeShader::SkeletalMesh, FName(ShaderNameStr),
FString::Printf(TEXT("Mobile base pass vertex shader%s"), DescSuffix)));
// dynamically lit shader FMobileDirectionalLightAndCSMPolicy
MobileBasePassShaderName(false, TEXT("FMobileDirectionalLightAndCSMPolicy"), bEnableLocalLights, bMobileHDR, bOnlySkyPermutation, ShaderNameStr);
ShaderTypeNamesAndDescriptions.FindOrAdd(FLocalVertexFactoryName)
.Add(FRepresentativeShaderInfo(ERepresentativeShader::DynamicallyLitObject, FName(ShaderNameStr),
FString::Printf(TEXT("Mobile base pass shader with only dynamic lighting%s"), DescSuffix)));
MobileBasePassShaderName(true, TEXT("FMobileDirectionalLightAndCSMPolicy"), bEnableLocalLights, bMobileHDR, bOnlySkyPermutation, ShaderNameStr);
ShaderTypeNamesAndDescriptions.FindOrAdd(FLocalVertexFactoryName)
.Add(FRepresentativeShaderInfo(ERepresentativeShader::StaticMesh, FName(ShaderNameStr),
FString::Printf(TEXT("Mobile base pass vertex shader%s"), DescSuffix)));
ShaderTypeNamesAndDescriptions.FindOrAdd(FGPUFactoryName)
.Add(FRepresentativeShaderInfo(ERepresentativeShader::SkeletalMesh, FName(ShaderNameStr),
FString::Printf(TEXT("Mobile base pass vertex shader%s"), DescSuffix)));
}
}
}
/**
* Gets instruction counts that best represent the likely usage of this material based on shading model and other factors.
* @param Results - an array of descriptions to be populated
*/
void FMaterialStatsUtils::GetRepresentativeInstructionCounts(TArray<FShaderInstructionsInfo>& Results, const FMaterialResource* Target)
{
TMap<FName, TArray<FRepresentativeShaderInfo>> ShaderTypeNamesAndDescriptions;
Results.Empty();
//when adding a shader type here be sure to update FPreviewMaterial::ShouldCache()
//so the shader type will get compiled with preview materials
const FMaterialShaderMap* MaterialShaderMap = Target->GetGameThreadShaderMap();
Only compile the shaders needed to gather shader platform stats in the Material Editor. # Results Modfiying WorldGridMaterial with two platforms open in platform stats. - We compile a fixed number of shaders (less than 10 per platform) now instead of the 1078 shaders (per platform) w/ WorldGridMaterial. - On average ProcessCompiledShaderMaps is 40x faster. (1727ms vs. 43ms) - In the worst cast ProcessCompiledShaderMaps is 10.9x faster. (4865ms vs 445ms) - The material editor in this scenario goes from unusable to useable. # Changes - Add `FMaterial::CacheGivenTypes` to compile just the shader types given to it. - Call `GetRepresentativeShaderTypesAndDescriptions` to gather the shader types we care about and only submit jobs to compile those shaders when generating platform stats. - Since we are no longer compile a complete shader map the ShaderCount is incorrect. Now we call `GetShaderTypes` of the `FMaterialResource` to gather the number of shaders in the material. This function doesn't trigger shader compilation which is important. - Adding const to the following functions: - FMaterial::GetShaderTypesForLayout - FMaterial::GetShaderTypes - FMaterial::GetShaderTypes is now ENGINE_API so we can call it from the Material Editor. - Add `TBasePassPSFCachedVolumeIndirectLightingPolicy` shader type to FMaterialStatsUtils::GetRepresentativeShaderTypesAndDescriptions. This shader has the worst case sampler count. This ensures we compile this shader and are able to query the worst case sampler count for the platform stats. This is very ad-hoc, and could be improved in the future. #rb Ben.Ingram #jira UE-138623 #preflight 623b4e4cc3399da9533282cc [CL 19481265 by Jason Nadro in ue5-main branch]
2022-03-23 13:03:01 -04:00
if (MaterialShaderMap)
{
GetRepresentativeShaderTypesAndDescriptions(ShaderTypeNamesAndDescriptions, Target);
TStaticArray<bool, (int32)ERepresentativeShader::Num> bShaderTypeAdded(InPlace, false);
if (Target->IsUIMaterial())
{
//for (const TPair<FName, FRepresentativeShaderInfo>& ShaderTypePair : ShaderTypeNamesAndDescriptions)
for (auto DescriptionPair : ShaderTypeNamesAndDescriptions)
{
auto& DescriptionArray = DescriptionPair.Value;
for (int32 i = 0; i < DescriptionArray.Num(); ++i)
{
const FRepresentativeShaderInfo& ShaderInfo = DescriptionArray[i];
if (!bShaderTypeAdded[(int32)ShaderInfo.ShaderType])
{
FShaderType* ShaderType = FindShaderTypeByName(ShaderInfo.ShaderName);
check(ShaderType);
const int32 NumInstructions = MaterialShaderMap->GetMaxNumInstructionsForShader(ShaderType);
FShaderInstructionsInfo Info;
Info.ShaderType = ShaderInfo.ShaderType;
Info.ShaderDescription = ShaderInfo.ShaderDescription;
Info.InstructionCount = NumInstructions;
Results.Push(Info);
bShaderTypeAdded[(int32)ShaderInfo.ShaderType] = true;
}
}
}
}
else
{
for (auto DescriptionPair : ShaderTypeNamesAndDescriptions)
{
FVertexFactoryType* FactoryType = FindVertexFactoryType(DescriptionPair.Key);
const FMeshMaterialShaderMap* MeshShaderMap = MaterialShaderMap->GetMeshShaderMap(FactoryType);
if (MeshShaderMap)
{
TMap<FHashedName, TShaderRef<FShader>> ShaderMap;
MeshShaderMap->GetShaderList(*MaterialShaderMap, ShaderMap);
auto& DescriptionArray = DescriptionPair.Value;
for (int32 i = 0; i < DescriptionArray.Num(); ++i)
{
const FRepresentativeShaderInfo& ShaderInfo = DescriptionArray[i];
if (!bShaderTypeAdded[(int32)ShaderInfo.ShaderType])
{
TShaderRef<FShader>* ShaderEntry = ShaderMap.Find(ShaderInfo.ShaderName);
if (ShaderEntry != nullptr)
{
FShaderType* ShaderType = (*ShaderEntry).GetType();
{
const int32 NumInstructions = MeshShaderMap->GetMaxNumInstructionsForShader(*MaterialShaderMap, ShaderType);
FShaderInstructionsInfo Info;
Info.ShaderType = ShaderInfo.ShaderType;
Info.ShaderDescription = ShaderInfo.ShaderDescription;
Info.InstructionCount = NumInstructions;
Results.Push(Info);
bShaderTypeAdded[(int32)ShaderInfo.ShaderType] = true;
}
}
}
}
}
}
}
}
}
Only compile the shaders needed to gather shader platform stats in the Material Editor. # Results Modfiying WorldGridMaterial with two platforms open in platform stats. - We compile a fixed number of shaders (less than 10 per platform) now instead of the 1078 shaders (per platform) w/ WorldGridMaterial. - On average ProcessCompiledShaderMaps is 40x faster. (1727ms vs. 43ms) - In the worst cast ProcessCompiledShaderMaps is 10.9x faster. (4865ms vs 445ms) - The material editor in this scenario goes from unusable to useable. # Changes - Add `FMaterial::CacheGivenTypes` to compile just the shader types given to it. - Call `GetRepresentativeShaderTypesAndDescriptions` to gather the shader types we care about and only submit jobs to compile those shaders when generating platform stats. - Since we are no longer compile a complete shader map the ShaderCount is incorrect. Now we call `GetShaderTypes` of the `FMaterialResource` to gather the number of shaders in the material. This function doesn't trigger shader compilation which is important. - Adding const to the following functions: - FMaterial::GetShaderTypesForLayout - FMaterial::GetShaderTypes - FMaterial::GetShaderTypes is now ENGINE_API so we can call it from the Material Editor. - Add `TBasePassPSFCachedVolumeIndirectLightingPolicy` shader type to FMaterialStatsUtils::GetRepresentativeShaderTypesAndDescriptions. This shader has the worst case sampler count. This ensures we compile this shader and are able to query the worst case sampler count for the platform stats. This is very ad-hoc, and could be improved in the future. #rb Ben.Ingram #jira UE-138623 #preflight 623b4e4cc3399da9533282cc [CL 19481265 by Jason Nadro in ue5-main branch]
2022-03-23 13:03:01 -04:00
void FMaterialStatsUtils::ExtractMatertialStatsInfo(EShaderPlatform ShaderPlatform, FShaderStatsInfo& OutInfo, const FMaterialResource* MaterialResource)
{
// extract potential errors
const ERHIFeatureLevel::Type MaterialFeatureLevel = MaterialResource->GetFeatureLevel();
FString FeatureLevelName;
GetFeatureLevelName(MaterialFeatureLevel, FeatureLevelName);
OutInfo.Empty();
TArray<FString> CompileErrors = MaterialResource->GetCompileErrors();
for (int32 ErrorIndex = 0; ErrorIndex < CompileErrors.Num(); ErrorIndex++)
{
OutInfo.StrShaderErrors += FString::Printf(TEXT("[%s] %s\n"), *FeatureLevelName, *CompileErrors[ErrorIndex]);
}
bool bNoErrors = OutInfo.StrShaderErrors.Len() == 0;
if (bNoErrors)
{
// extract instructions info
TArray<FMaterialStatsUtils::FShaderInstructionsInfo> ShaderInstructionInfo;
GetRepresentativeInstructionCounts(ShaderInstructionInfo, MaterialResource);
for (int32 InstructionIndex = 0; InstructionIndex < ShaderInstructionInfo.Num(); InstructionIndex++)
{
FShaderStatsInfo::FContent Content;
Content.StrDescription = ShaderInstructionInfo[InstructionIndex].InstructionCount > 0 ? FString::Printf(TEXT("%u"), ShaderInstructionInfo[InstructionIndex].InstructionCount) : TEXT("n/a");
Content.StrDescriptionLong = ShaderInstructionInfo[InstructionIndex].InstructionCount > 0 ?
FString::Printf(TEXT("%s: %u instructions"), *ShaderInstructionInfo[InstructionIndex].ShaderDescription, ShaderInstructionInfo[InstructionIndex].InstructionCount) :
TEXT("Offline shader compiler not available or an error was encountered!");
OutInfo.ShaderInstructionCount.Add(ShaderInstructionInfo[InstructionIndex].ShaderType, Content);
}
// extract samplers info
const int32 SamplersUsed = FMath::Max(MaterialResource->GetSamplerUsage(), 0);
const int32 MaxSamplers = GetExpectedFeatureLevelMaxTextureSamplers(MaterialResource->GetFeatureLevel());
OutInfo.SamplersCount.StrDescription = FString::Printf(TEXT("%u/%u"), SamplersUsed, MaxSamplers);
OutInfo.SamplersCount.StrDescriptionLong = FString::Printf(TEXT("%s samplers: %u/%u"), TEXT("Texture"), SamplersUsed, MaxSamplers);
Only compile the shaders needed to gather shader platform stats in the Material Editor. # Results Modfiying WorldGridMaterial with two platforms open in platform stats. - We compile a fixed number of shaders (less than 10 per platform) now instead of the 1078 shaders (per platform) w/ WorldGridMaterial. - On average ProcessCompiledShaderMaps is 40x faster. (1727ms vs. 43ms) - In the worst cast ProcessCompiledShaderMaps is 10.9x faster. (4865ms vs 445ms) - The material editor in this scenario goes from unusable to useable. # Changes - Add `FMaterial::CacheGivenTypes` to compile just the shader types given to it. - Call `GetRepresentativeShaderTypesAndDescriptions` to gather the shader types we care about and only submit jobs to compile those shaders when generating platform stats. - Since we are no longer compile a complete shader map the ShaderCount is incorrect. Now we call `GetShaderTypes` of the `FMaterialResource` to gather the number of shaders in the material. This function doesn't trigger shader compilation which is important. - Adding const to the following functions: - FMaterial::GetShaderTypesForLayout - FMaterial::GetShaderTypes - FMaterial::GetShaderTypes is now ENGINE_API so we can call it from the Material Editor. - Add `TBasePassPSFCachedVolumeIndirectLightingPolicy` shader type to FMaterialStatsUtils::GetRepresentativeShaderTypesAndDescriptions. This shader has the worst case sampler count. This ensures we compile this shader and are able to query the worst case sampler count for the platform stats. This is very ad-hoc, and could be improved in the future. #rb Ben.Ingram #jira UE-138623 #preflight 623b4e4cc3399da9533282cc [CL 19481265 by Jason Nadro in ue5-main branch]
2022-03-23 13:03:01 -04:00
// extract estimated sample info
uint32 NumVSTextureSamples = 0, NumPSTextureSamples = 0;
MaterialResource->GetEstimatedNumTextureSamples(NumVSTextureSamples, NumPSTextureSamples);
OutInfo.TextureSampleCount.StrDescription = FString::Printf(TEXT("VS(%u), PS(%u)"), NumVSTextureSamples, NumPSTextureSamples);
OutInfo.TextureSampleCount.StrDescriptionLong = FString::Printf(TEXT("Texture Lookups (Est.): Vertex(%u), Pixel(%u)"), NumVSTextureSamples, NumPSTextureSamples);
// extract estimated VT info
const uint32 NumVirtualTextureLookups = MaterialResource->GetEstimatedNumVirtualTextureLookups();
OutInfo.VirtualTextureLookupCount.StrDescription = FString::Printf(TEXT("%u"), NumVirtualTextureLookups);
OutInfo.VirtualTextureLookupCount.StrDescriptionLong = FString::Printf(TEXT("Virtual Texture Lookups (Est.): %u"), NumVirtualTextureLookups);
// extract interpolators info
uint32 UVScalarsUsed, CustomInterpolatorScalarsUsed;
MaterialResource->GetUserInterpolatorUsage(UVScalarsUsed, CustomInterpolatorScalarsUsed);
const uint32 TotalScalars = UVScalarsUsed + CustomInterpolatorScalarsUsed;
const uint32 MaxScalars = FMath::DivideAndRoundUp(TotalScalars, 4u) * 4;
OutInfo.InterpolatorsCount.StrDescription = FString::Printf(TEXT("%u/%u"), TotalScalars, MaxScalars);
OutInfo.InterpolatorsCount.StrDescriptionLong = FString::Printf(TEXT("User interpolators: %u/%u Scalars (%u/4 Vectors) (TexCoords: %i, Custom: %i)"),
TotalScalars, MaxScalars, MaxScalars / 4, UVScalarsUsed, CustomInterpolatorScalarsUsed);
Only compile the shaders needed to gather shader platform stats in the Material Editor. # Results Modfiying WorldGridMaterial with two platforms open in platform stats. - We compile a fixed number of shaders (less than 10 per platform) now instead of the 1078 shaders (per platform) w/ WorldGridMaterial. - On average ProcessCompiledShaderMaps is 40x faster. (1727ms vs. 43ms) - In the worst cast ProcessCompiledShaderMaps is 10.9x faster. (4865ms vs 445ms) - The material editor in this scenario goes from unusable to useable. # Changes - Add `FMaterial::CacheGivenTypes` to compile just the shader types given to it. - Call `GetRepresentativeShaderTypesAndDescriptions` to gather the shader types we care about and only submit jobs to compile those shaders when generating platform stats. - Since we are no longer compile a complete shader map the ShaderCount is incorrect. Now we call `GetShaderTypes` of the `FMaterialResource` to gather the number of shaders in the material. This function doesn't trigger shader compilation which is important. - Adding const to the following functions: - FMaterial::GetShaderTypesForLayout - FMaterial::GetShaderTypes - FMaterial::GetShaderTypes is now ENGINE_API so we can call it from the Material Editor. - Add `TBasePassPSFCachedVolumeIndirectLightingPolicy` shader type to FMaterialStatsUtils::GetRepresentativeShaderTypesAndDescriptions. This shader has the worst case sampler count. This ensures we compile this shader and are able to query the worst case sampler count for the platform stats. This is very ad-hoc, and could be improved in the future. #rb Ben.Ingram #jira UE-138623 #preflight 623b4e4cc3399da9533282cc [CL 19481265 by Jason Nadro in ue5-main branch]
2022-03-23 13:03:01 -04:00
// Extract total shader count w/o having to compile shaders.
FPlatformTypeLayoutParameters LayoutParams;
LayoutParams.InitializeForPlatform(nullptr);
Only compile the shaders needed to gather shader platform stats in the Material Editor. # Results Modfiying WorldGridMaterial with two platforms open in platform stats. - We compile a fixed number of shaders (less than 10 per platform) now instead of the 1078 shaders (per platform) w/ WorldGridMaterial. - On average ProcessCompiledShaderMaps is 40x faster. (1727ms vs. 43ms) - In the worst cast ProcessCompiledShaderMaps is 10.9x faster. (4865ms vs 445ms) - The material editor in this scenario goes from unusable to useable. # Changes - Add `FMaterial::CacheGivenTypes` to compile just the shader types given to it. - Call `GetRepresentativeShaderTypesAndDescriptions` to gather the shader types we care about and only submit jobs to compile those shaders when generating platform stats. - Since we are no longer compile a complete shader map the ShaderCount is incorrect. Now we call `GetShaderTypes` of the `FMaterialResource` to gather the number of shaders in the material. This function doesn't trigger shader compilation which is important. - Adding const to the following functions: - FMaterial::GetShaderTypesForLayout - FMaterial::GetShaderTypes - FMaterial::GetShaderTypes is now ENGINE_API so we can call it from the Material Editor. - Add `TBasePassPSFCachedVolumeIndirectLightingPolicy` shader type to FMaterialStatsUtils::GetRepresentativeShaderTypesAndDescriptions. This shader has the worst case sampler count. This ensures we compile this shader and are able to query the worst case sampler count for the platform stats. This is very ad-hoc, and could be improved in the future. #rb Ben.Ingram #jira UE-138623 #preflight 623b4e4cc3399da9533282cc [CL 19481265 by Jason Nadro in ue5-main branch]
2022-03-23 13:03:01 -04:00
TArray<FDebugShaderTypeInfo> OutShaderInfo;
MaterialResource->GetShaderTypes(ShaderPlatform, LayoutParams, OutShaderInfo);
int TotalShadersForMaterial = 0;
for (const FDebugShaderTypeInfo& ShaderInfo : OutShaderInfo)
{
TotalShadersForMaterial += ShaderInfo.ShaderTypes.Num();
for (const FDebugShaderPipelineInfo& PipelineInfo : ShaderInfo.Pipelines)
{
TotalShadersForMaterial += PipelineInfo.ShaderTypes.Num();
}
}
OutInfo.ShaderCount.StrDescription = FString::Printf(TEXT("%u"), TotalShadersForMaterial);
OutInfo.ShaderCount.StrDescriptionLong = FString::Printf(TEXT("Total Shaders: %u"), TotalShadersForMaterial);
}
}
/*end FMaterialStatsUtils */
/***********************************************************************************************************************/