internal static MyShaderIdentity ComputeShaderIdentity(string source, MyShaderProfile profile) { var bytes = Encoding.UTF8.GetBytes(source); byte[] compressed; using (var ms = new MemoryStream()) { using (var gz = new GZipStream(ms, CompressionMode.Compress)) { gz.Write(bytes, 0, bytes.Length); } compressed = ms.ToArray(); } byte[] hash = m_md5.ComputeHash(bytes); var builder = new StringBuilder(hash.Length); for (int i = 0; i < hash.Length; i++) { builder.Append(hash[i].ToString("X2")); } return(new MyShaderIdentity(builder.ToString(), compressed, profile)); }
internal static byte[] Compile(string filepath, ShaderMacro[] macros, MyShaderProfile profile, string sourceDescriptor, bool invalidateCache) { bool wasCached; string compileLog; var result = Compile(filepath, macros, profile, sourceDescriptor, MyCompilationSymbols.EnableShaderDebuggingInNSight, invalidateCache, out wasCached, out compileLog); if (!wasCached) { string message = "WARNING: Shader was not precompiled - " + sourceDescriptor + " @ profile " + profile + " with defines " + macros.GetString(); MyRender11.Log.WriteLine(message); } if (!string.IsNullOrEmpty(compileLog)) { string descriptor = sourceDescriptor + " " + ProfileToString(profile) + " " + macros.GetString(); if (result != null) { Debug.WriteLine(String.Format("Compilation of shader {0} notes:\n{1}", descriptor, compileLog)); } else { string message = String.Format("Compilation of shader {0} errors:\n{1}", descriptor, compileLog); MyRender11.Log.WriteLine(message); Debug.WriteLine(message); Debugger.Break(); } } return(result); }
private static void PreCompile(string filepath, List <ShaderMacro> macros, MyShaderProfile profile, string descriptor, string vertexLayoutString, float progress, OnShaderCacheProgressDelegate onShaderCacheProgress) { var macrosArray = macros.ToArray(); bool wasCached; string compileLog; if (onShaderCacheProgress != null) { onShaderCacheProgress(progress, descriptor, MyShaders.ProfileToString(profile), vertexLayoutString, macrosArray.GetString(), "", false); } var compiled = MyShaders.Compile(filepath, macrosArray, profile, descriptor, true, false, out wasCached, out compileLog); if (onShaderCacheProgress != null) { if (wasCached) { onShaderCacheProgress(progress, descriptor, MyShaders.ProfileToString(profile), vertexLayoutString, macrosArray.GetString(), "skipped", false); } else if (compileLog != null) { onShaderCacheProgress(progress, descriptor, MyShaders.ProfileToString(profile), vertexLayoutString, macrosArray.GetString(), (compiled == null ? "errors:\n" : "warnings:\n") + compileLog, compiled == null); } } }
internal static MyShaderIdentity ComputeShaderIdentity(string source, MyShaderProfile profile) { var bytes = Encoding.UTF8.GetBytes(source); byte[] compressed; using (var ms = new MemoryStream()) { using (var gz = new GZipStream(ms, CompressionMode.Compress)) { gz.Write(bytes, 0, bytes.Length); } compressed = ms.ToArray(); } byte[] hash = m_md5.ComputeHash(bytes); var builder = new StringBuilder(hash.Length); for (int i = 0; i < hash.Length; i++) { builder.Append(hash[i].ToString("X2")); } return new MyShaderIdentity(builder.ToString(), compressed, profile); }
internal static byte[] Compile(string filepath, ShaderMacro[] macros, MyShaderProfile profile, string sourceDescriptor, bool optimize, bool invalidateCache, out bool wasCached, out string compileLog) { ProfilerShort.Begin("MyShaders.Compile"); var globalMacros = GlobalShaderMacros; if (globalMacros.Length != 0) { var macroList = new List <ShaderMacro>(); macroList.AddRange(globalMacros); macroList.AddRange(macros); macros = macroList.ToArray(); } string function = ProfileEntryPoint(profile); string profileName = ProfileToString(profile); wasCached = false; compileLog = null; ProfilerShort.Begin("MyShaders.Preprocess"); string errors; string preprocessedSource = PreprocessShader(filepath, macros, out errors); if (preprocessedSource == null) { compileLog = errors; return(null); } // modify preprocessor to be readable for NSight if (MyCompilationSymbols.EnableShaderDebuggingInNSight) { preprocessedSource = Regex.Replace(preprocessedSource, "#line [^\n]*\n", ""); } MyShaderIdentity identity = null; if (!invalidateCache && !MyCompilationSymbols.EnableShaderDebuggingInNSight) { identity = MyShaderCache.ComputeShaderIdentity(preprocessedSource, profile); byte[] cached; if (MyShaderCache.TryFetch(identity, out cached)) { wasCached = true; ProfilerShort.End(); ProfilerShort.End(); return(cached); } } ProfilerShort.End(); try { string descriptor = sourceDescriptor + " " + profile + " " + macros.GetString(); CompilationResult compilationResult; if (MyCompilationSymbols.EnableShaderDebuggingInNSight) { if (MyCompilationSymbols.EnableShaderPreprocessorInNSight) { compilationResult = ShaderBytecode.Compile(preprocessedSource, function, profileName, 0, 0, macros, new MyIncludeProcessor(filepath)); } else { compilationResult = ShaderBytecode.CompileFromFile(filepath, function, profileName, 0, 0, macros, new MyIncludeProcessor(filepath)); } } else { compilationResult = ShaderBytecode.Compile(preprocessedSource, function, profileName, optimize ? ShaderFlags.OptimizationLevel3 : ShaderFlags.None, EffectFlags.None, filepath); } if (DUMP_CODE) { var disassembly = compilationResult.Bytecode.Disassemble(DisassemblyFlags.EnableColorCode | DisassemblyFlags.EnableInstructionNumbering); string asmPath; if (MyRender11.DebugMode) { asmPath = Path.GetFileName(descriptor + "__DEBUG.html"); } else { asmPath = Path.GetFileName(descriptor + "__O3.html"); } using (var writer = new StreamWriter(Path.Combine(MyFileSystem.ContentPath, "ShaderOutput", asmPath))) { writer.Write(disassembly); } } if (compilationResult.Message != null) { compileLog = compilationResult.Message; } if (!MyCompilationSymbols.EnableShaderDebuggingInNSight && compilationResult.Bytecode != null && compilationResult.Bytecode.Data.Length > 0) { MyShaderCache.Store(identity, compilationResult.Bytecode.Data); } return(compilationResult.Bytecode != null ? compilationResult.Bytecode.Data : null); } catch (Exception e) { Debug.WriteLine(preprocessedSource); compileLog = e.Message; } finally { ProfilerShort.End(); } return(null); }
public MyShaderIdentity(string hash, byte[] source, MyShaderProfile profile) { Hash = hash; Source = source; Profile = profile; }
private static void GenerateInternal(CacheGenerator generatorDesc, OnShaderCacheProgressDelegate onShaderCacheProgress) { #if XB1 System.Diagnostics.Debug.Assert(false, "TODO for XB1."); #else // !XB1 var shaderPath = Path.Combine(MyShaders.ShadersPath); string[] files = GetShadersRecursively(shaderPath, generatorDesc.Ignores); var macroVariants = new List <string[]>(); var macroVariantMandatory = new List <bool>(); for (int i = 0; i < files.Length; i++) { float progress = (float)i * 100 / files.Length; string file = files[i]; string fileText = file.Remove(0, shaderPath.Length); using (var reader = new StreamReader(file)) { var source = reader.ReadToEnd(); bool any = false; if (source.IndexOf(ANNOTATION_SKIP) != -1) { continue; } for (MyShaderProfile profile = 0; profile < MyShaderProfile.count; profile++) { string function = MyShaders.ProfileEntryPoint(profile); if (source.Contains(function)) { // generate list of macro variants macroVariants.Clear(); macroVariantMandatory.Clear(); // global ones macroVariants.Add(new[] { "MS_SAMPLE_COUNT 2", "MS_SAMPLE_COUNT 4", "MS_SAMPLE_COUNT 8", "FXAA_ENABLED" }); macroVariantMandatory.Add(false); // shader specific ones int defineEndIndex = 0; while (true) { int defineIndex = source.IndexOf('@', defineEndIndex); if (defineIndex == -1) { break; } int advance = -1; bool mandatory = false; defineIndex++; if (CheckAnnotation(source, defineIndex, ANNOTATION_DEFINE_MANDATORY)) { advance = ANNOTATION_DEFINE_MANDATORY.Length; mandatory = true; } else if (CheckAnnotation(source, defineIndex, ANNOTATION_DEFINE)) { advance = ANNOTATION_DEFINE.Length; } if (advance == -1) { defineEndIndex++; continue; } defineIndex += advance; defineEndIndex = source.IndexOf("\n", defineIndex); if (defineEndIndex == -1) { defineEndIndex = source.Length; } var define = source.Substring(defineIndex, defineEndIndex - defineIndex); define = define.Trim(); var defineEntries = define.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); macroVariants.Add(defineEntries); macroVariantMandatory.Add(mandatory); } // init macro counters based on mandatory flag var counters = new int[macroVariants.Count]; for (int j = 0; j < macroVariants.Count; j++) { counters[j] = macroVariantMandatory[j] ? 1 : 0; } // compile all variants bool finished = false; while (!finished) { // prepare macros var macros = new List <ShaderMacro>(); for (int j = 0; j < macroVariants.Count; j++) { if (counters[j] > 0) { var define = macroVariants[j][counters[j] - 1]; var defineSplit = define.Split((char[])null, StringSplitOptions.RemoveEmptyEntries); MyDebug.AssertDebug(defineSplit.Length == 1 || defineSplit.Length == 2, "Invalid define @ " + fileText + ": " + define); if (defineSplit.Length > 1) { macros.Add(new ShaderMacro(defineSplit[0].Trim(), defineSplit[1].Trim())); } else { macros.Add(new ShaderMacro(defineSplit[0].Trim(), null)); } } } // compile PreCompile(file, macros, profile, fileText, "", progress, onShaderCacheProgress); any = true; // increase variants counters int countersIndex = counters.Length - 1; do { counters[countersIndex]++; if (counters[countersIndex] > macroVariants[countersIndex].Length) { counters[countersIndex] = macroVariantMandatory[countersIndex] ? 1 : 0; if (countersIndex == 0) { finished = true; } countersIndex--; } else { break; } } while (countersIndex >= 0); } } } if (!any && onShaderCacheProgress != null) { onShaderCacheProgress(progress, file, "", "", "", "No entry point found.", true); } } } #endif // !XB1 }
internal static string ProfileEntryPoint(MyShaderProfile val) { switch (val) { case MyShaderProfile.vs_5_0: return "__vertex_shader"; case MyShaderProfile.ps_5_0: return "__pixel_shader"; case MyShaderProfile.gs_5_0: return "__geometry_shader"; case MyShaderProfile.cs_5_0: return "__compute_shader"; default: throw new Exception(); } }
internal static string ProfileToString(MyShaderProfile val) { switch (val) { case MyShaderProfile.vs_5_0: return "vs_5_0"; case MyShaderProfile.ps_5_0: return "ps_5_0"; case MyShaderProfile.gs_5_0: return "gs_5_0"; case MyShaderProfile.cs_5_0: return "cs_5_0"; default: throw new Exception(); } }
internal static byte[] Compile(string filepath, ShaderMacro[] macros, MyShaderProfile profile, string sourceDescriptor, bool optimize, bool invalidateCache, out bool wasCached, out string compileLog) { ProfilerShort.Begin("MyShaders.Compile"); var globalMacros = GlobalShaderMacros; if (globalMacros.Length != 0) { var macroList = new List<ShaderMacro>(); macroList.AddRange(globalMacros); macroList.AddRange(macros); macros = macroList.ToArray(); } string function = ProfileEntryPoint(profile); string profileName = ProfileToString(profile); wasCached = false; compileLog = null; ProfilerShort.Begin("MyShaders.Preprocess"); string errors; string preprocessedSource = PreprocessShader(filepath, macros, out errors); if (preprocessedSource == null) { compileLog = errors; return null; } // modify preprocessor to be readable for NSight if (MyCompilationSymbols.EnableShaderDebuggingInNSight) { preprocessedSource = Regex.Replace(preprocessedSource, "#line [^\n]*\n", ""); } MyShaderIdentity identity = null; if (!invalidateCache && !MyCompilationSymbols.EnableShaderDebuggingInNSight) { identity = MyShaderCache.ComputeShaderIdentity(preprocessedSource, profile); byte[] cached; if (MyShaderCache.TryFetch(identity, out cached)) { wasCached = true; ProfilerShort.End(); ProfilerShort.End(); return cached; } } ProfilerShort.End(); try { string descriptor = sourceDescriptor + " " + profile + " " + macros.GetString(); CompilationResult compilationResult; if (MyCompilationSymbols.EnableShaderDebuggingInNSight) { if (MyCompilationSymbols.EnableShaderPreprocessorInNSight) compilationResult = ShaderBytecode.Compile(preprocessedSource, function, profileName, 0, 0, macros, new MyIncludeProcessor(filepath)); else { compilationResult = ShaderBytecode.CompileFromFile(filepath, function, profileName, 0, 0, macros, new MyIncludeProcessor(filepath)); } } else compilationResult = ShaderBytecode.Compile(preprocessedSource, function, profileName, optimize ? ShaderFlags.OptimizationLevel3 : ShaderFlags.None, EffectFlags.None, filepath); if (DUMP_CODE) { var disassembly = compilationResult.Bytecode.Disassemble(DisassemblyFlags.EnableColorCode | DisassemblyFlags.EnableInstructionNumbering); string asmPath; if (MyRender11.DebugMode) { asmPath = Path.GetFileName(descriptor + "__DEBUG.html"); } else { asmPath = Path.GetFileName(descriptor + "__O3.html"); } using (var writer = new StreamWriter(Path.Combine(MyFileSystem.ContentPath, "ShaderOutput", asmPath))) { writer.Write(disassembly); } } if (compilationResult.Message != null) compileLog = compilationResult.Message; if (!MyCompilationSymbols.EnableShaderDebuggingInNSight && compilationResult.Bytecode != null && compilationResult.Bytecode.Data.Length > 0) MyShaderCache.Store(identity, compilationResult.Bytecode.Data); return compilationResult.Bytecode != null ? compilationResult.Bytecode.Data : null; } catch (Exception e) { Debug.WriteLine(preprocessedSource); compileLog = e.Message; } finally { ProfilerShort.End(); } return null; }
internal static byte[] Compile(string filepath, ShaderMacro[] macros, MyShaderProfile profile, string sourceDescriptor, bool invalidateCache) { bool wasCached; string compileLog; var result = Compile(filepath, macros, profile, sourceDescriptor, !MyRender11.DebugMode, invalidateCache, out wasCached, out compileLog); if (!wasCached) { string message = "WARNING: Shader was not precompiled - " + sourceDescriptor + " @ profile " + profile + " with defines " + macros.GetString(); MyRender11.Log.WriteLine(message); } if (!string.IsNullOrEmpty(compileLog)) { string descriptor = sourceDescriptor + " " + ProfileToString(profile) + " " + macros.GetString(); if (result != null) { Debug.WriteLine(String.Format("Compilation of shader {0} notes:\n{1}", descriptor, compileLog)); } else { string message = String.Format("Compilation of shader {0} errors:\n{1}", descriptor, compileLog); MyRender11.Log.WriteLine(message); Debug.WriteLine(message); Debugger.Break(); } } return result; }