public static List <Struct> GetAllStructsFromShaderFile(ShaderFile shaderFile) { MatchCollection matches = Regex.Matches(shaderFile.Content, StructRegex, RegexOptions.Multiline); List <Struct> structs = new List <Struct>(); // For each structure in the code foreach (Match match in matches) { string name = match.Groups[1].ToString().Trim(); string content = match.Groups[2].ToString(); if (name.Length == 0) { // Structs should have a name. If they don't, it's probably a mistake. Make sure we catch this. throw new Exception("Nameless structs not allowed. Culprit:\n" + content); } Struct s = new Struct(name); // For each element separated by a semi-colon ; foreach (string e in content.Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries)) { s.AddStructElement(e.Trim()); } // Flag if struct is a constant buffer or not s.DetectStructType(); structs.Add(s); } return(structs); }
// Processes all headers from a shader file and compiles every permutation public static void Compile(ShaderFile inShaderFile) { Console.WriteLine("Compiling shaders for file \"{0}\"", inShaderFile.FullPath); ShaderCompilerDX shaderCompiler; switch (Config.Compiler) { case Compiler.FXC: shaderCompiler = new ShaderCompilerFXC(); break; case Compiler.DXC: shaderCompiler = new ShaderCompilerDXC(); break; default: throw new Exception("Uknown compiler \"" + Config.Compiler + "\""); } foreach (HeaderInfo header in inShaderFile.Headers) { shaderCompiler.Compile(header, inShaderFile); } }
// Processes all headers from a shader file and compiles every permutation public void Compile(HeaderInfo inHeader, ShaderFile ioShaderFile) { Console.WriteLine("HEADER:\t\t" + inHeader.GetDebugString()); // Shader code as header file or binary file // TODO: Only header files for now bool header_file = true; string export_option = header_file ? "Fh" : "Fo"; string cmd_input_file = ioShaderFile.FullPath; string cmd_output_file = CreateCommand(export_option, inHeader.GetGeneratedFileName(ioShaderFile)); string cmd_variable_name = header_file ? CreateCommand("Vn", "g_" + inHeader.Name) : ""; string cmd_entry_point = CreateCommand("E", inHeader.EntryPoint); string cmd_profile = CreateCommand("T", EnumUtils.ToDescription(inHeader.Type).ToLower() + "_" + EnumUtils.ToDescription(Config.ShaderModel)); string cmd_optimization = CreateCommand("Od"); string cmd_debug_info = Config.EnableDebugInformation ? CreateCommand("Zi") : ""; string cmd_defines = GenerateDefines(inHeader, Config.ShaderModel); string cmd_nologo = CreateCommand("nologo"); // Don't output to file in Test. This should just output the shader code in the console if (Arguments.Operation == Arguments.OperationType.Test) { cmd_variable_name = ""; cmd_output_file = ""; } string args = CombineCommands(cmd_input_file, cmd_output_file, cmd_variable_name, cmd_entry_point, cmd_profile, cmd_optimization, cmd_debug_info, cmd_defines, cmd_nologo); string compiler_exe = GetCompilerPath(); Process process = Process.Start(compiler_exe); process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.StartInfo.UseShellExecute = false; process.StartInfo.CreateNoWindow = true; process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; process.StartInfo.Arguments = args; process.Start(); // To avoid deadlocks, use an asynchronous read operation on at least one of the streams. process.StandardOutput.ReadToEnd(); process.WaitForExit(); ioShaderFile.DidCompile = (process.ExitCode == 0); if (!ioShaderFile.DidCompile) { string errorMessage = process.StandardError.ReadToEnd() + "Failed with commandline:\n" + compiler_exe + " " + args + "\n\n"; throw new Exception(errorMessage); //throw new Exception(process.StandardOutput.ReadToEnd()); } //Console.WriteLine(process.StandardError.ReadToEnd()); }
private static void CreateDependencies() { // List all DIRECT and INDIRECT dependencies FROM each ShaderFiles foreach (KeyValuePair <UInt32, ShaderFile> pair in CurrentDB) { ShaderFile current_file = pair.Value; FindDependenciesInFile(current_file, current_file.Dependencies); } }
public string GetGeneratedFileName(ShaderFile inShaderFile) { // TODO: Only header files for now bool header_file = true; string output_extension = header_file ? Config.GeneratedHeaderExtension : ".bin"; string shader_name = inShaderFile.GetFileName() + "_" + Name + "_" + EnumUtils.ToDescription(Type); string shader_output_file = Path.Combine(Config.GeneratedFolderPath, shader_name) + output_extension; return(shader_output_file); }
public void ProcessSingleFile(ShaderFile inShaderFile) { // Get all structs Structs.AddRange(Struct.GetAllStructsFromShaderFile(inShaderFile)); // Compile if (inShaderFile.ShouldCompile) { ShaderCompiler.Compile(inShaderFile); } }
private static void ProcessDeletedShaderFile(ShaderFile inShaderFile) { string full_path = Config.GeneratedFolderPath; // Delete obsolete generated H files foreach (string filename in inShaderFile.GeneratedFiles) { // Don't process non shader compiled files if (!filename.EndsWith(Config.GeneratedHeaderExtension)) { throw new Exception("New generated files? Make sure they are handled properly"); } File.Delete(Path.Combine(full_path, filename)); } }
// Recursive function to find all dependencies FROM a given shader file private static void FindDependenciesInFile(ShaderFile inShaderFile, List <ShaderFile> outList) { string shader_directory = Path.GetDirectoryName(inShaderFile.FullPath); List <string> includes = inShaderFile.ParseIncludes(); foreach (string include in includes) { string include_path = Path.GetFullPath(Path.Combine(shader_directory, include)); // Check the file actually exists if (File.Exists(include_path)) { // Get shader file from full path UInt32 file_hash = GetFilenameHash(include_path); ShaderFile include_shader_file = GetValue(CurrentDB, file_hash); // Check that a ShaderFile of this path exists if (include_shader_file != null) { // Check that we didn't parse this include already. Otherwise it means we have cyclic dependencies if (!outList.Contains(include_shader_file)) { outList.Add(include_shader_file); // Recursion. Find all dependencies of all included files FindDependenciesInFile(include_shader_file, outList); } else { throw new Exception(String.Format("Include path \"{0}\" in file \"{1}\" is a cyclic dependency.", include, inShaderFile.FullPath)); } } else { throw new Exception(String.Format("Include path \"{0}\" in file \"{1}\" exists, but wasn't parsed by the ShaderFileGatherer." + "Extension missing in configuration?", include, inShaderFile.FullPath)); } } else { throw new Exception(String.Format("Include path \"{0}\" in file \"{1}\" doesn't exist", include, inShaderFile.FullPath)); } } }
private static void ProcessFile(string inFullPathToFile) { // Make sure file ends with one of the shader extension if (Config.ShaderExtensions.Any(x => inFullPathToFile.EndsWith(x))) { string file_content = File.ReadAllText(inFullPathToFile); DateTime modified_time = File.GetLastWriteTime(inFullPathToFile); // Create hash from file name, to check with previous version of the file UInt32 hash = GetFilenameHash(inFullPathToFile); ShaderFile shaderFile = new ShaderFile { Content = file_content, ShouldCompile = true, FullPath = inFullPathToFile, FilenameHash = GetFilenameHash(inFullPathToFile), ModifiedTime = modified_time, DidCompile = true, Dependencies = new List <ShaderFile>() }; // Find all headers in files shaderFile.ParseHeaders(); // Find generated file names in advance shaderFile.GeneratedFiles = new List <string>(); foreach (HeaderInfo header in shaderFile.Headers) { shaderFile.GeneratedFiles.Add(header.GetGeneratedFileName(shaderFile)); } if (CurrentDB.ContainsKey(hash)) { throw new Exception("Same file shouldn't be processed twice"); } CurrentDB[hash] = shaderFile; } }
// Go through all previous elements in the DB to detect ShaderFiles that were deleted, added, or modified // Set their ShouldCompile member variable to true if we need to recompile them // Returns true if the previous DB doesn't match the current DB private static bool UpdateDadaBase() { bool db_changed = false; // Process previous files in DB. Could still exist, or be deleted foreach (KeyValuePair <UInt32, ShaderFile> pair in PreviousDB) { ShaderFile previous_file = pair.Value; ShaderFile current_file = CurrentDB.GetValue(pair.Key); // File was not deleted if (current_file != null) { // Retry shaders that didn't compile last time bool file_changed = previous_file.DidCompile == false; // Recompile shaders that were modified file_changed |= (current_file.ModifiedTime != previous_file.ModifiedTime); // Recompile moved/renamed shaders file_changed |= (current_file.FilenameHash != previous_file.FilenameHash); // Recompile if generated files don't exist if (previous_file.GeneratedFiles.Any(filename => !File.Exists(filename))) { file_changed = true; } current_file.ShouldCompile = file_changed; db_changed |= file_changed; } // File was deleted else { ProcessDeletedShaderFile(previous_file); db_changed = true; } } // Process added files foreach (KeyValuePair <UInt32, ShaderFile> pair in CurrentDB) { ShaderFile current_file = pair.Value; ShaderFile previous_file = PreviousDB.GetValue(pair.Key); // Current file was added if (previous_file == null) { current_file.ShouldCompile = true; db_changed = true; } } // Process dependencies foreach (KeyValuePair <UInt32, ShaderFile> pair in CurrentDB) { ShaderFile current_file = pair.Value; // Go through all direct and indirect dependencies foreach (ShaderFile dependency in current_file.Dependencies) { // Recompile if at least one of them was changed if (dependency.ShouldCompile) { current_file.ShouldCompile = true; break; } } } return(db_changed); }