/** * Construct the final microcode from the compiled and verified shader source. * @param ShaderOutput - Where to store the microcode and parameter map. * @param InShaderSource - GLSL source with input/output signature. * @param SourceLen - The length of the GLSL source code. */ static void BuildShaderOutput( FShaderCompilerOutput& ShaderOutput, const FShaderCompilerInput& ShaderInput, const ANSICHAR* InShaderSource, int32 SourceLen, GLSLVersion Version ) { const ANSICHAR* USFSource = InShaderSource; CrossCompiler::FHlslccHeader CCHeader; if (!CCHeader.Read(USFSource, SourceLen)) { UE_LOG(LogOpenGLShaderCompiler, Error, TEXT("Bad hlslcc header found")); } if (*USFSource != '#') { UE_LOG(LogOpenGLShaderCompiler, Error, TEXT("Bad hlslcc header found! Missing '#'!")); } FOpenGLCodeHeader Header = {0}; FShaderParameterMap& ParameterMap = ShaderOutput.ParameterMap; EShaderFrequency Frequency = (EShaderFrequency)ShaderOutput.Target.Frequency; TBitArray<> UsedUniformBufferSlots; UsedUniformBufferSlots.Init(false, 32); // Write out the magic markers. Header.GlslMarker = 0x474c534c; switch (Frequency) { case SF_Vertex: Header.FrequencyMarker = 0x5653; break; case SF_Pixel: Header.FrequencyMarker = 0x5053; break; case SF_Geometry: Header.FrequencyMarker = 0x4753; break; case SF_Hull: Header.FrequencyMarker = 0x4853; break; case SF_Domain: Header.FrequencyMarker = 0x4453; break; case SF_Compute: Header.FrequencyMarker = 0x4353; break; default: UE_LOG(LogOpenGLShaderCompiler, Fatal, TEXT("Invalid shader frequency: %d"), (int32)Frequency); } static const FString AttributePrefix = TEXT("in_ATTRIBUTE"); static const FString GL_Prefix = TEXT("gl_"); for (auto& Input : CCHeader.Inputs) { // Only process attributes for vertex shaders. if (Frequency == SF_Vertex && Input.Name.StartsWith(AttributePrefix)) { int32 AttributeIndex = ParseNumber(*Input.Name + AttributePrefix.Len()); Header.Bindings.InOutMask |= (1 << AttributeIndex); } // Record user-defined input varyings else if (!Input.Name.StartsWith(GL_Prefix)) { FOpenGLShaderVarying Var; Var.Location = Input.Index; Var.Varying = ParseIdentifierANSI(Input.Name); Header.Bindings.InputVaryings.Add(Var); } } // Generate vertex attribute remapping table. // This is used on devices where GL_MAX_VERTEX_ATTRIBS < 16 if (Frequency == SF_Vertex) { uint32 AttributeMask = Header.Bindings.InOutMask; int32 NextAttributeSlot = 0; Header.Bindings.VertexRemappedMask = 0; for (int32 AttributeIndex = 0; AttributeIndex < 16; AttributeIndex++, AttributeMask >>= 1) { if (AttributeMask & 0x1) { Header.Bindings.VertexRemappedMask |= (1 << NextAttributeSlot); Header.Bindings.VertexAttributeRemap[AttributeIndex] = NextAttributeSlot++; } else { Header.Bindings.VertexAttributeRemap[AttributeIndex] = -1; } } }
static int32 Run(const FRunInfo& RunInfo) { ILanguageSpec* Language = nullptr; FCodeBackend* Backend = nullptr; uint32 Flags = HLSLCC_PackUniforms; Flags |= RunInfo.bValidate ? 0 : HLSLCC_NoValidation; Flags |= RunInfo.bRunCPP ? 0 : HLSLCC_NoPreprocess; Flags |= RunInfo.bPackIntoUBs ? HLSLCC_PackUniformsIntoUniformBuffers : 0; Flags |= RunInfo.bUseDX11Clip ? HLSLCC_DX11ClipSpace : 0; Flags |= RunInfo.bFlattenUBs ? HLSLCC_FlattenUniformBuffers : 0; Flags |= RunInfo.bFlattenUBStructs ? HLSLCC_FlattenUniformBufferStructures : 0; Flags |= RunInfo.bGroupFlattenUBs ? HLSLCC_GroupFlattenedUniformBuffers : 0; Flags |= RunInfo.bCSE ? HLSLCC_ApplyCommonSubexpressionElimination : 0; Flags |= RunInfo.bExpandExpressions ? HLSLCC_ExpandSubexpressions : 0; Flags |= RunInfo.bSeparateShaders ? HLSLCC_SeparateShaderObjects : 0; FGlslLanguageSpec GlslLanguage(RunInfo.Target == HCT_FeatureLevelES2); FGlslCodeBackend GlslBackend(Flags, RunInfo.Target); FMetalLanguageSpec MetalLanguage; FMetalCodeBackend MetalBackend(Flags, RunInfo.Target); switch (RunInfo.BackEnd) { case CCT::FRunInfo::BE_Metal: Language = &MetalLanguage; Backend = &MetalBackend; break; case CCT::FRunInfo::BE_OpenGL: Language = &GlslLanguage; Backend = &GlslBackend; Flags |= HLSLCC_DX11ClipSpace; break; default: return 1; } FString HLSLShaderSource; if (RunInfo.bUseNew) { if (RunInfo.bList) { if (!FFileHelper::LoadFileToString(HLSLShaderSource, *RunInfo.InputFile)) { UE_LOG(LogCrossCompilerTool, Error, TEXT("Couldn't load Input file '%s'!"), *RunInfo.InputFile); return 1; } TArray<FString> List; if (!FFileHelper::LoadANSITextFileToStrings(*RunInfo.InputFile, &IFileManager::Get(), List)) { return 1; } int32 Count = 0; for (auto& File : List) { FString HLSLShader; if (!FFileHelper::LoadFileToString(HLSLShader, *File)) { UE_LOG(LogCrossCompilerTool, Error, TEXT("Couldn't load Input file '%s'!"), *File); continue; } UE_LOG(LogCrossCompilerTool, Log, TEXT("%d: %s"), Count++, *File); if (!CrossCompiler::Parser::Parse(HLSLShader, File, false)) { UE_LOG(LogCrossCompilerTool, Log, TEXT("Error compiling '%s'!"), *File); return 1; } } } else { if (RunInfo.bRunCPP) { //GMalloc->DumpAllocatorStats(*FGenericPlatformOutputDevices::GetLog()); if (!Preprocess(RunInfo.InputFile, HLSLShaderSource)) { UE_LOG(LogCrossCompilerTool, Log, TEXT("Error during preprocessor on '%s'!"), *RunInfo.InputFile); return 1; } //GMalloc->DumpAllocatorStats(*FGenericPlatformOutputDevices::GetLog()); } else { if (!FFileHelper::LoadFileToString(HLSLShaderSource, *RunInfo.InputFile)) { UE_LOG(LogCrossCompilerTool, Error, TEXT("Couldn't load Input file '%s'!"), *RunInfo.InputFile); return 1; } } if (RunInfo.bPreprocessOnly) { return 0; } if (!CrossCompiler::Parser::Parse(HLSLShaderSource, *RunInfo.InputFile, true)) { UE_LOG(LogCrossCompilerTool, Log, TEXT("Error compiling '%s'!"), *RunInfo.InputFile); return 1; } } //Scanner.Dump(); return 0; } else { if (!FFileHelper::LoadFileToString(HLSLShaderSource, *RunInfo.InputFile)) { UE_LOG(LogCrossCompilerTool, Error, TEXT("Couldn't load Input file '%s'!"), *RunInfo.InputFile); return 1; } } ANSICHAR* ShaderSource = 0; ANSICHAR* ErrorLog = 0; FHlslCrossCompilerContext Context(Flags, RunInfo.Frequency, RunInfo.Target); if (Context.Init(TCHAR_TO_ANSI(*RunInfo.InputFile), Language)) { Context.Run( TCHAR_TO_ANSI(*HLSLShaderSource), TCHAR_TO_ANSI(*RunInfo.Entry), Backend, &ShaderSource, &ErrorLog); } if (ErrorLog) { FString OutError(ANSI_TO_TCHAR(ErrorLog)); UE_LOG(LogCrossCompilerTool, Warning, TEXT("%s"), *OutError); } if (ShaderSource) { FString OutSource(ANSI_TO_TCHAR(ShaderSource)); UE_LOG(LogCrossCompilerTool, Display, TEXT("%s"), *OutSource); if (RunInfo.OutputFile.Len() > 0) { FFileHelper::SaveStringToFile(OutSource, *RunInfo.OutputFile); } } if (ShaderSource) { const ANSICHAR* USFSource = ShaderSource; CrossCompiler::FHlslccHeader CCHeader; int32 Len = FCStringAnsi::Strlen(USFSource); if (!CCHeader.Read(USFSource, Len)) { UE_LOG(LogCrossCompilerTool, Error, TEXT("Bad hlslcc header found")); } if (Language == &GlslLanguage && *USFSource != '#') { UE_LOG(LogCrossCompilerTool, Error, TEXT("Bad hlslcc header found! Missing '#'!")); } } free(ShaderSource); free(ErrorLog); return 0; }