Example #1
0
        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));
        }
Example #2
0
        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);
                }
            }
        }
Example #4
0
        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);
        }
Example #5
0
        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);
        }
Example #6
0
 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
        }
Example #8
0
        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();
            }
        }
Example #9
0
        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();
            }
        }
Example #10
0
        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;
        }
Example #11
0
        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;
        }
Example #12
0
 public MyShaderIdentity(string hash, byte[] source, MyShaderProfile profile)
 {
     Hash = hash;
     Source = source;
     Profile = profile;
 }