MemoryStream ExtractMetadataAndStream(string path) { if (ShaderFileCache.TryLoad(path, out string text)) { DependencyPaths.Add(path); if (MetadataParsing.Parse(path, text, Stages, MacroGroups, IncludeParsingErrors)) { //We write ascii into the bytes regardless of the source text so that fxc is kept happy. var bytes = Encoding.ASCII.GetBytes(text); return(new MemoryStream(bytes)); } } return(null); }
private static void CollectCompilationTargets(string source, string workingPath, ShaderFileCache shaderFileCache, ShaderCompilationCache loadedCache, ShaderCompilationCache cache, List <ShaderCompilationResult> errors, List <ShaderCompilationTarget> compilationTargets) { if (!shaderFileCache.TryLoad(source, out string shaderCode)) { lock (errors) { errors.Add(new ShaderCompilationResult("Shader", "", "", source, 0, 0, 0, 0, "Could not find file " + source)); } return; } //Only compile this shader if the shader has been modified since the previous compile. var currentTimeStamp = File.GetLastWriteTime(source).Ticks; if (loadedCache.ShaderFlags == cache.ShaderFlags && loadedCache.TimeStamps.TryGetValue(source, out long previousTimeStamp)) //If this file was contained before, we MIGHT be able to skip its compilation. { if (currentTimeStamp <= previousTimeStamp) //If the file hasn't been updated, we MIGHT be able to skip. { //Check the timestamps associated with the dependencies of this file. //If any are newer than the previous snapshot, skip. bool allowSkip = true; if (loadedCache.Dependencies.TryGetValue(source, out HashSet <string> loadedDependencyPaths)) { foreach (var dependency in loadedDependencyPaths) { //The loadedCache is guaranteed to contain a time stamp for any dependency referenced, //because the only time any dependency is added to the list the dependency is ALSO put into the timestamps list. var previousDependencyTimeStamp = loadedCache.TimeStamps[dependency]; var currentDependencyTimeStamp = File.GetLastWriteTime(dependency).Ticks; if (currentDependencyTimeStamp > previousDependencyTimeStamp) { //One of the dependencies has been updated. This shader must be compiled. allowSkip = false; break; } } } else { //One of the dependencies could not be found in the old cache. Implies a new dependency was added; must compile. allowSkip = false; } if (allowSkip) { Console.WriteLine($"Shader up to date: {Path.GetFileName(source)}"); cache.CopyFrom(source, loadedCache); return; } } } var localWorkingPath = Path.GetDirectoryName(source); var include = new IncludeHandler(shaderFileCache, workingPath, localWorkingPath); var stages = new List <ShaderStage>(); var macroGroups = new List <MacroGroup>(); var metadataParsingErrors = new List <MetadataParsingError>(); MetadataParsing.Parse(source, shaderCode, stages, macroGroups, metadataParsingErrors); //Prepass to collect include metadata. Seems hacky, oh well. try { ShaderBytecode.Preprocess(shaderCode, null, include); } catch (CompilationException e) { if (ParseCompilerResult(e.Message, out string filePath, out int lineBegin, out int columnBegin, out int lineEnd, out int columnEnd, out string description)) { var errorChecker = new Regex("error X(?<errorCode>[0-9]{4}): "); var errorCode = errorChecker.Match(e.Message).Groups["errorCode"].Value; lock (errors) { errors.Add(new ShaderCompilationResult("Shader", errorCode, "", source, lineBegin, columnBegin, lineEnd, columnEnd, description)); } }