Files
UnrealEngine/Engine/Source/Runtime/RenderCore/Private/ShaderStableKeyDebugInfoReader.cpp
2025-05-18 13:04:45 +08:00

105 lines
3.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
/**
* Code for reading .shk files and using that information to map shader hashes back to human-readable identifies.
*/
#include "ShaderStableKeyDebugInfoReader.h"
#include "PipelineCacheUtilities.h"
#include "RHIResources.h"
// Disable in Shipping just in case (also shaderpipelineutils aren't available there)
#define UE_WITH_SHK_READER (!UE_BUILD_SHIPPING)
bool UE::ShaderUtils::FShaderStableKeyDebugInfoReader::Initialize(const FString& ShaderStableKeyFile)
{
bool bResult = false;
#if UE_WITH_SHK_READER
TArray<FStableShaderKeyAndValue> StableArray;
if (UE::PipelineCacheUtilities::LoadStableKeysFile(ShaderStableKeyFile, StableArray))
{
ShaderHashesToSource.Empty();
for (const FStableShaderKeyAndValue& StableKey : StableArray)
{
TSet<FStableShaderKeyAndValue>& DedupShaders = ShaderHashesToSource.FindOrAdd(StableKey.OutputHash);
DedupShaders.Add(StableKey);
}
bResult = true;
}
#endif // UE_WITH_SHK_READER
return bResult;
}
FString UE::ShaderUtils::FShaderStableKeyDebugInfoReader::GetShaderStableNameOptions(const FSHAHash& ShaderHash, int32 MaxOptionsToInclude)
{
FString Output; // FIXME: change to builder
#if UE_WITH_SHK_READER
if (TSet<FStableShaderKeyAndValue>* SourceSet = ShaderHashesToSource.Find(ShaderHash))
{
Output += FString::Printf(TEXT("hash %s maps to %d shaders"), *ShaderHash.ToString(), SourceSet->Num());
if (SourceSet->Num() > MaxOptionsToInclude)
{
Output += FString::Printf(TEXT(", limiting output to %d"), MaxOptionsToInclude);
}
Output += TEXT(":\n");
int32 OptionsToInclude = FMath::Min(MaxOptionsToInclude, SourceSet->Num());
for (const FStableShaderKeyAndValue& StableKey : *SourceSet)
{
if (--OptionsToInclude < 0)
{
break;
}
Output += FString::Printf(TEXT("\t%s\n"), *StableKey.ToString());
}
}
else
{
Output += FString::Printf(TEXT("hash %s not in the key file(s)! (were key file(s) produced in the same cook as this build?)\n"), *ShaderHash.ToString());
}
#endif // UE_WITH_SHK_READER
return Output;
}
FString UE::ShaderUtils::FShaderStableKeyDebugInfoReader::GetPSOStableNameOptions(const FGraphicsPipelineStateInitializer& Initializer, int32 MaxOptionsToInclude)
{
FString Output; // FIXME: change to builder
#if UE_WITH_SHK_READER
#define UE_FPTSM_DUMPSHADER(ShaderType) \
if (FRHIShader* Shader = Initializer.BoundShaderState.Get##ShaderType()) \
{ \
const FSHAHash& Hash = Shader->GetHash(); \
Output += FString::Printf(TEXT("%s: %s"), TEXT(#ShaderType), *GetShaderStableNameOptions(Hash, MaxOptionsToInclude)); \
}
Output += FString::Printf(TEXT("---- begin FGraphicsPipelineStateInitializer -----\n"));
UE_FPTSM_DUMPSHADER(VertexShader);
UE_FPTSM_DUMPSHADER(MeshShader);
UE_FPTSM_DUMPSHADER(AmplificationShader);
UE_FPTSM_DUMPSHADER(PixelShader);
UE_FPTSM_DUMPSHADER(GeometryShader);
#undef UE_FPTSM_DUMPSHADER
Output += FString::Printf(TEXT("----- end -----\n"));
#endif // UE_WITH_SHK_READER
return Output;
}
void UE::ShaderUtils::FShaderStableKeyDebugInfoReader::DumpPSOToLogIfConfigured(const FGraphicsPipelineStateInitializer& Initializer)
{
#if UE_WITH_SHK_READER
UE_LOG(LogInit, Log, TEXT("%s"), *GetPSOStableNameOptions(Initializer));
#endif // UE_WITH_SHK_READER
}