bool AreGlobalShadersComplete(const TCHAR* TypeNameSubstring) { EShaderPlatform Platform = GRHIShaderPlatform; TShaderMap<FGlobalShaderType>* GlobalShaderMap = GGlobalShaderMap[Platform]; if (GlobalShaderMap) { for(TLinkedList<FShaderType*>::TIterator ShaderTypeIt(FShaderType::GetTypeList());ShaderTypeIt;ShaderTypeIt.Next()) { FGlobalShaderType* GlobalShaderType = ShaderTypeIt->GetGlobalShaderType(); if (GlobalShaderType && FPlatformString::Strstr(GlobalShaderType->GetName(), TypeNameSubstring) != NULL && GlobalShaderType->ShouldCache(Platform)) { if (!GlobalShaderMap->HasShader(GlobalShaderType)) { return false; } } } return true; } return false; }
bool IsGlobalShaderMapComplete(const TCHAR* TypeNameSubstring) { for (int32 i = 0; i < SP_NumPlatforms; ++i) { EShaderPlatform Platform = (EShaderPlatform)i; TShaderMap<FGlobalShaderType>* GlobalShaderMap = GGlobalShaderMap[Platform]; if (GlobalShaderMap) { for (TLinkedList<FShaderType*>::TIterator ShaderTypeIt(FShaderType::GetTypeList()); ShaderTypeIt; ShaderTypeIt.Next()) { FGlobalShaderType* GlobalShaderType = ShaderTypeIt->GetGlobalShaderType(); if (GlobalShaderType && (TypeNameSubstring == nullptr || (FPlatformString::Strstr(GlobalShaderType->GetName(), TypeNameSubstring) != nullptr)) && GlobalShaderType->ShouldCache(Platform)) { if (!GlobalShaderMap->HasShader(GlobalShaderType)) { return false; } } } } } return true; }
bool IsGlobalShaderMapComplete() { EShaderPlatform Platform = GRHIShaderPlatform; TShaderMap<FGlobalShaderType>* GlobalShaderMap = GGlobalShaderMap[Platform]; if (GlobalShaderMap) { for(TLinkedList<FShaderType*>::TIterator ShaderTypeIt(FShaderType::GetTypeList());ShaderTypeIt;ShaderTypeIt.Next()) { FGlobalShaderType* GlobalShaderType = ShaderTypeIt->GetGlobalShaderType(); if (GlobalShaderType && GlobalShaderType->ShouldCache(Platform)) { if (!GlobalShaderMap->HasShader(GlobalShaderType)) { return false; } } } return true; } return false; }
bool FMeshMaterialShaderMap::IsComplete( const FMeshMaterialShaderMap* MeshShaderMap, EShaderPlatform Platform, const FMaterial* Material, FVertexFactoryType* InVertexFactoryType, bool bSilent ) { // Iterate over all mesh material shader types. for (TLinkedList<FShaderType*>::TIterator ShaderTypeIt(FShaderType::GetTypeList());ShaderTypeIt;ShaderTypeIt.Next()) { FMeshMaterialShaderType* ShaderType = ShaderTypeIt->GetMeshMaterialShaderType(); if (ShaderType && !IsMeshShaderComplete(MeshShaderMap, Platform, Material, ShaderType, nullptr, InVertexFactoryType, bSilent)) { return false; } } // Iterate over all pipeline types for (TLinkedList<FShaderPipelineType*>::TIterator ShaderPipelineIt(FShaderPipelineType::GetTypeList());ShaderPipelineIt;ShaderPipelineIt.Next()) { const FShaderPipelineType* ShaderPipelineType = *ShaderPipelineIt; if (ShaderPipelineType->IsMeshMaterialTypePipeline()) { auto& Stages = ShaderPipelineType->GetStages(); // Verify all the ShouldCache are in sync int32 NumShouldCache = 0; for (int32 Index = 0; Index < Stages.Num(); ++Index) { auto* ShaderType = Stages[Index]->GetMeshMaterialShaderType(); if (ShouldCacheMeshShader(ShaderType, Platform, Material, InVertexFactoryType)) { ++NumShouldCache; } else { break; } } if (NumShouldCache == Stages.Num()) { // Now check the completeness of the shader map for (int32 Index = 0; Index < Stages.Num(); ++Index) { auto* ShaderType = Stages[Index]->GetMeshMaterialShaderType(); if (ShaderType && !IsMeshShaderComplete(MeshShaderMap, Platform, Material, ShaderType, ShaderPipelineType, InVertexFactoryType, bSilent)) { return false; } } } } } return true; }
FShaderType* FindShaderTypeByName(const TCHAR* ShaderTypeName) { for(TLinkedList<FShaderType*>::TIterator ShaderTypeIt(FShaderType::GetTypeList());ShaderTypeIt;ShaderTypeIt.Next()) { if(!FCString::Stricmp(ShaderTypeIt->GetName(),ShaderTypeName)) { return *ShaderTypeIt; } } return NULL; }
FGlobalShaderMapId::FGlobalShaderMapId(EShaderPlatform Platform) { TArray<FShaderType*> ShaderTypes; for (TLinkedList<FShaderType*>::TIterator ShaderTypeIt(FShaderType::GetTypeList()); ShaderTypeIt; ShaderTypeIt.Next()) { FGlobalShaderType* GlobalShaderType = ShaderTypeIt->GetGlobalShaderType(); if (GlobalShaderType && GlobalShaderType->ShouldCache(Platform)) { ShaderTypes.Add(GlobalShaderType); } } ShaderTypes.Sort(FCompareShaderTypes()); for (int32 TypeIndex = 0; TypeIndex < ShaderTypes.Num(); TypeIndex++) { FShaderTypeDependency Dependency; Dependency.ShaderType = ShaderTypes[TypeIndex]; Dependency.SourceHash = ShaderTypes[TypeIndex]->GetSourceHash(); ShaderTypeDependencies.Add(Dependency); } }
/** * Makes sure all global shaders are loaded and/or compiled for the passed in platform. * Note: if compilation is needed, this only kicks off the compile. * * @param Platform Platform to verify global shaders for */ void VerifyGlobalShaders(EShaderPlatform Platform, bool bLoadedFromCacheFile) { check(IsInGameThread()); check(!FPlatformProperties::IsServerOnly()); check(GGlobalShaderMap[Platform]); UE_LOG(LogShaders, Log, TEXT("Verifying Global Shaders for %s"), *LegacyShaderPlatformToShaderFormat(Platform).ToString()); // Ensure that the global shader map contains all global shader types. TShaderMap<FGlobalShaderType>* GlobalShaderMap = GetGlobalShaderMap(Platform); const bool bEmptyMap = GlobalShaderMap->IsEmpty(); if (bEmptyMap) { UE_LOG(LogShaders, Warning, TEXT(" Empty global shader map, recompiling all global shaders")); } TArray<FShaderCompileJob*> GlobalShaderJobs; for(TLinkedList<FShaderType*>::TIterator ShaderTypeIt(FShaderType::GetTypeList());ShaderTypeIt;ShaderTypeIt.Next()) { FGlobalShaderType* GlobalShaderType = ShaderTypeIt->GetGlobalShaderType(); if(GlobalShaderType && GlobalShaderType->ShouldCache(Platform)) { if(!GlobalShaderMap->HasShader(GlobalShaderType)) { bool bErrorOnMissing = bLoadedFromCacheFile; if (FPlatformProperties::RequiresCookedData()) { // We require all shaders to exist on cooked platforms because we can't compile them. bErrorOnMissing = true; } if (bErrorOnMissing) { UE_LOG(LogShaders, Fatal,TEXT("Missing global shader %s, Please make sure cooking was successful."), GlobalShaderType->GetName()); } if (!bEmptyMap) { UE_LOG(LogShaders, Warning, TEXT(" %s"), GlobalShaderType->GetName()); } // Compile this global shader type. GlobalShaderType->BeginCompileShader(Platform, GlobalShaderJobs); } } } if (GlobalShaderJobs.Num() > 0) { GShaderCompilingManager->AddJobs(GlobalShaderJobs, true, true); const bool bAllowAsynchronousGlobalShaderCompiling = // OpenGL requires that global shader maps are compiled before attaching // primitives to the scene as it must be able to find FNULLPS. // TODO_OPENGL: Allow shaders to be compiled asynchronously. !IsOpenGLPlatform(GMaxRHIShaderPlatform) && GShaderCompilingManager->AllowAsynchronousShaderCompiling(); if (!bAllowAsynchronousGlobalShaderCompiling) { TArray<int32> ShaderMapIds; ShaderMapIds.Add(GlobalShaderMapId); GShaderCompilingManager->FinishCompilation(TEXT("Global"), ShaderMapIds); } } }
void FMeshMaterialShaderMap::LoadMissingShadersFromMemory( const FSHAHash& MaterialShaderMapHash, const FMaterial* Material, EShaderPlatform Platform) { for (TLinkedList<FShaderType*>::TIterator ShaderTypeIt(FShaderType::GetTypeList());ShaderTypeIt;ShaderTypeIt.Next()) { FMeshMaterialShaderType* ShaderType = ShaderTypeIt->GetMeshMaterialShaderType(); if (ShaderType && ShouldCacheMeshShader(ShaderType, Platform, Material, VertexFactoryType) && !HasShader((FShaderType*)ShaderType)) { const FShaderId ShaderId(MaterialShaderMapHash, nullptr, VertexFactoryType, (FShaderType*)ShaderType, FShaderTarget(ShaderType->GetFrequency(), Platform)); FShader* FoundShader = ((FShaderType*)ShaderType)->FindShaderById(ShaderId); if (FoundShader) { AddShader((FShaderType*)ShaderType, FoundShader); } } } // Try to find necessary FShaderPipelineTypes in memory for (TLinkedList<FShaderPipelineType*>::TIterator ShaderPipelineIt(FShaderPipelineType::GetTypeList());ShaderPipelineIt;ShaderPipelineIt.Next()) { const FShaderPipelineType* PipelineType = *ShaderPipelineIt; if (PipelineType && PipelineType->IsMeshMaterialTypePipeline() && !HasShaderPipeline(PipelineType)) { auto& Stages = PipelineType->GetStages(); int32 NumShaders = 0; for (const FShaderType* Shader : Stages) { FMeshMaterialShaderType* ShaderType = (FMeshMaterialShaderType*)Shader->GetMeshMaterialShaderType(); if (ShaderType && ShouldCacheMeshShader(ShaderType, Platform, Material, VertexFactoryType)) { ++NumShaders; } else { break; } } if (NumShaders == Stages.Num()) { TArray<FShader*> ShadersForPipeline; for (auto* Shader : Stages) { FMeshMaterialShaderType* ShaderType = (FMeshMaterialShaderType*)Shader->GetMeshMaterialShaderType(); if (!HasShader(ShaderType)) { const FShaderId ShaderId(MaterialShaderMapHash, PipelineType->ShouldOptimizeUnusedOutputs() ? PipelineType : nullptr, VertexFactoryType, ShaderType, FShaderTarget(ShaderType->GetFrequency(), Platform)); FShader* FoundShader = ShaderType->FindShaderById(ShaderId); if (FoundShader) { AddShader(ShaderType, FoundShader); ShadersForPipeline.Add(FoundShader); } } } if (ShadersForPipeline.Num() == NumShaders && !HasShaderPipeline(PipelineType)) { auto* Pipeline = new FShaderPipeline(PipelineType, ShadersForPipeline); AddShaderPipeline(PipelineType, Pipeline); } } } } }
/** * Enqueues compilation for all shaders for a material and vertex factory type. * @param Material - The material to compile shaders for. * @param VertexFactoryType - The vertex factory type to compile shaders for. * @param Platform - The platform to compile for. */ uint32 FMeshMaterialShaderMap::BeginCompile( uint32 ShaderMapId, const FMaterialShaderMapId& InShaderMapId, const FMaterial* Material, FShaderCompilerEnvironment* MaterialEnvironment, EShaderPlatform Platform, TArray<FShaderCommonCompileJob*>& NewJobs ) { if (!VertexFactoryType) { return 0; } uint32 NumShadersPerVF = 0; TSet<FString> ShaderTypeNames; // Iterate over all mesh material shader types. TMap<FShaderType*, FShaderCompileJob*> SharedShaderJobs; for (TLinkedList<FShaderType*>::TIterator ShaderTypeIt(FShaderType::GetTypeList());ShaderTypeIt;ShaderTypeIt.Next()) { FMeshMaterialShaderType* ShaderType = ShaderTypeIt->GetMeshMaterialShaderType(); if (ShaderType && ShouldCacheMeshShader(ShaderType, Platform, Material, VertexFactoryType)) { // Verify that the shader map Id contains inputs for any shaders that will be put into this shader map check(InShaderMapId.ContainsVertexFactoryType(VertexFactoryType)); check(InShaderMapId.ContainsShaderType(ShaderType)); NumShadersPerVF++; // only compile the shader if we don't already have it if (!HasShader(ShaderType)) { // Compile this mesh material shader for this material and vertex factory type. auto* Job = ShaderType->BeginCompileShader( ShaderMapId, Platform, Material, MaterialEnvironment, VertexFactoryType, nullptr, NewJobs ); check(!SharedShaderJobs.Find(ShaderType)); SharedShaderJobs.Add(ShaderType, Job); } } } // Now the pipeline jobs; if it's a shareable pipeline, do not add duplicate jobs for (TLinkedList<FShaderPipelineType*>::TIterator ShaderPipelineIt(FShaderPipelineType::GetTypeList());ShaderPipelineIt;ShaderPipelineIt.Next()) { const FShaderPipelineType* Pipeline = *ShaderPipelineIt; if (Pipeline->IsMeshMaterialTypePipeline()) { auto& StageTypes = Pipeline->GetStages(); int32 NumShaderStagesToCompile = 0; for (auto* Shader : StageTypes) { const FMeshMaterialShaderType* ShaderType = Shader->GetMeshMaterialShaderType(); if (ShouldCacheMeshShader(ShaderType, Platform, Material, VertexFactoryType)) { ++NumShaderStagesToCompile; } else { break; } } if (NumShaderStagesToCompile == StageTypes.Num()) { // Verify that the shader map Id contains inputs for any shaders that will be put into this shader map check(InShaderMapId.ContainsShaderPipelineType(Pipeline)); if (Pipeline->ShouldOptimizeUnusedOutputs()) { NumShadersPerVF += NumShaderStagesToCompile; TArray<FMeshMaterialShaderType*> ShaderStagesToCompile; for (auto* Shader : StageTypes) { const FMeshMaterialShaderType* ShaderType = Shader->GetMeshMaterialShaderType(); // Verify that the shader map Id contains inputs for any shaders that will be put into this shader map check(InShaderMapId.ContainsVertexFactoryType(VertexFactoryType)); check(InShaderMapId.ContainsShaderType(ShaderType)); ShaderStagesToCompile.Add((FMeshMaterialShaderType*)ShaderType); } // Make a pipeline job with all the stages FMeshMaterialShaderType::BeginCompileShaderPipeline(ShaderMapId, Platform, Material, MaterialEnvironment, VertexFactoryType, Pipeline, ShaderStagesToCompile, NewJobs); } else { // If sharing shaders amongst pipelines, add this pipeline as a dependency of an existing job for (const FShaderType* ShaderType : StageTypes) { FShaderCompileJob** Job = SharedShaderJobs.Find(ShaderType); checkf(Job, TEXT("Couldn't find existing shared job for mesh shader %s on pipeline %s!"), ShaderType->GetName(), Pipeline->GetName()); auto* SingleJob = (*Job)->GetSingleShaderJob(); auto& PipelinesToShare = SingleJob->SharingPipelines.FindOrAdd(VertexFactoryType); check(!PipelinesToShare.Contains(Pipeline)); PipelinesToShare.Add(Pipeline); } } } } } if (NumShadersPerVF > 0) { UE_LOG(LogShaders, Verbose, TEXT(" %s - %u shaders"), VertexFactoryType->GetName(), NumShadersPerVF); } return NumShadersPerVF; }