Пример #1
0
        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);
        }
Пример #2
0
        // 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);
            }
        }
Пример #3
0
        // 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());
        }
Пример #4
0
 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);
     }
 }
Пример #5
0
        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);
        }
Пример #6
0
        public void ProcessSingleFile(ShaderFile inShaderFile)
        {
            // Get all structs
            Structs.AddRange(Struct.GetAllStructsFromShaderFile(inShaderFile));

            // Compile
            if (inShaderFile.ShouldCompile)
            {
                ShaderCompiler.Compile(inShaderFile);
            }
        }
Пример #7
0
        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));
            }
        }
Пример #8
0
        // 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));
                }
            }
        }
Пример #9
0
        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;
            }
        }
Пример #10
0
        // 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);
        }