private static void PreCompile(string source, List <ShaderMacro> macros, MyShadersDefines.Profiles profile, string descriptor, string vertexLayoutString, float progress, OnShaderCacheProgressDelegate onShaderCacheProgress) { var macrosArray = macros.ToArray(); bool wasCached; string compileLog; if (onShaderCacheProgress != null) { onShaderCacheProgress(progress, descriptor, MyShadersDefines.ProfileToString(profile), vertexLayoutString, macrosArray.GetString(), "", false); } var compiled = MyShaders.Compile(source, macrosArray, profile, descriptor, true, false, out wasCached, out compileLog); if (onShaderCacheProgress != null) { string message = ""; if (wasCached) { onShaderCacheProgress(progress, descriptor + vertexLayoutString, MyShadersDefines.ProfileToString(profile), vertexLayoutString, macrosArray.GetString(), "skipped", false); } else if (compileLog != null) { onShaderCacheProgress(progress, descriptor + vertexLayoutString, MyShadersDefines.ProfileToString(profile), vertexLayoutString, macrosArray.GetString(), (compiled == null ? "errors:\n" : "warnings:\n") + compileLog, compiled == null); } } }
internal static byte[] Compile(string source, ShaderMacro[] macros, MyShadersDefines.Profiles profile, string sourceDescriptor, bool invalidateCache) { bool wasCached; string compileLog; var result = Compile(source, 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 + " " + MyShadersDefines.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); } } return(result); }
private static void GenerateInternal(OnShaderCacheProgressDelegate onShaderCacheProgress) { #if XB1 System.Diagnostics.Debug.Assert(false, "TODO for XB1."); #else // !XB1 var shaderPath = Path.Combine(MyFileSystem.ContentPath, MyShadersDefines.ShadersContentPath); string[] files = Directory.GetFiles(shaderPath, "*.hlsl"); 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 (MyShadersDefines.Profiles profile = 0; profile < MyShadersDefines.Profiles.count; profile++) { string function = MyShadersDefines.ProfileEntryPoint(profile); if (source.Contains(function)) { // generate list of macro variants macroVariants.Clear(); macroVariantMandatory.Clear(); // global ones //macroVariants.Add(new[] {"DEBUG"}); //macroVariantMandatory.Add(false); 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; bool skip = false; 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); } if (skip) { continue; } // 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(source, 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 byte[] Compile(string source, ShaderMacro[] macros, MyShadersDefines.Profiles profile, string sourceDescriptor, bool optimize, bool invalidateCache, out bool wasCached, out string compileLog) { ProfilerShort.Begin("MyShaders.Compile"); string function = MyShadersDefines.ProfileEntryPoint(profile); string profileName = MyShadersDefines.ProfileToString(profile); wasCached = false; compileLog = null; ProfilerShort.Begin("MyShaders.Preprocess"); string preprocessedSource = PreprocessShader(source, macros); var key = MyShaderCache.CalculateKey(preprocessedSource, function, profileName); if (!invalidateCache) { var cached = MyShaderCache.TryFetch(key); if (cached != null) { wasCached = true; ProfilerShort.End(); ProfilerShort.End(); return(cached); } } ProfilerShort.End(); try { string descriptor = sourceDescriptor + " " + profile + " " + macros.GetString(); CompilationResult compilationResult = ShaderBytecode.Compile(preprocessedSource, function, profileName, optimize ? ShaderFlags.OptimizationLevel3 : 0, 0, null, null, descriptor); 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 = ExtendedErrorMessage(source, compilationResult.Message) + DumpShaderSource(key, preprocessedSource); } if (compilationResult.Bytecode.Data.Length > 0) { MyShaderCache.Store(key.ToString(), compilationResult.Bytecode.Data); } return(compilationResult.Bytecode.Data); } catch (CompilationException e) { Debug.WriteLine(preprocessedSource); compileLog = ExtendedErrorMessage(source, e.Message) + DumpShaderSource(key, preprocessedSource); } finally { ProfilerShort.End(); } return(null); }