using System; using System.IO; using System.Collections.Generic; using UnityEditor; using UnityEditor.Build; using UnityEditor.Build.Reporting; using UnityEditor.Rendering; using UnityEngine; using UnityEngine.Rendering; namespace ShaderControl { class ShaderDebugBuildProcessor : IPreprocessShaders, IPostprocessBuildWithReport { ShadersBuildInfo shadersBuildInfo; public static ShadersBuildInfo CheckShadersBuildStore(ShadersBuildInfo shadersBuildInfo) { if (shadersBuildInfo == null) { string filename = GetStoredDataPath(); shadersBuildInfo = AssetDatabase.LoadAssetAtPath(filename); if (shadersBuildInfo != null) { return shadersBuildInfo; } } // Check if scriptable object exists string path = GetStoredDataPath(); if (!File.Exists(path)) { string dir = Path.GetDirectoryName(path); Directory.CreateDirectory(dir); shadersBuildInfo = ScriptableObject.CreateInstance(); AssetDatabase.CreateAsset(shadersBuildInfo, path); AssetDatabase.SaveAssets(); } return shadersBuildInfo; } public void OnPostprocessBuild(BuildReport report) { SaveResults(); } public int callbackOrder { get { return 0; } } static string GetStoredDataPath() { // Locate shader control path string[] paths = AssetDatabase.GetAllAssetPaths(); for (int k = 0; k < paths.Length; k++) { if (paths[k].EndsWith("/ShaderControl/Editor", StringComparison.InvariantCultureIgnoreCase)) { return paths[k] + "/Resources/BuiltShaders.asset"; } } return null; } void SaveResults() { SCWindow.SetEditorPrefBool("QUICK_BUILD", false); if (shadersBuildInfo != null) { shadersBuildInfo.creationDateTicks = DateTime.Now.Ticks; EditorUtility.SetDirty(shadersBuildInfo); string filename = GetStoredDataPath(); if (filename == null) { Debug.LogError("Shader Control path not found."); } else { AssetDatabase.SaveAssets(); } } SCWindow.issueRefresh = 0; } public void OnProcessShader( Shader shader, ShaderSnippetData snippet, IList shaderCompilerData) { try { bool skipCompilation = false; if (SCWindow.GetEditorPrefBool("QUICK_BUILD", false)) { skipCompilation = true; } if (shadersBuildInfo == null) { string filename = GetStoredDataPath(); shadersBuildInfo = AssetDatabase.LoadAssetAtPath(filename); if (shadersBuildInfo == null) { return; } } ShaderBuildInfo sb = shadersBuildInfo.GetShader(shader.name); if (sb == null) { sb = new ShaderBuildInfo(); sb.name = shader.name; sb.simpleName = SCShader.GetSimpleName(sb.name); sb.path = AssetDatabase.GetAssetPath(shader); sb.isInternal = string.IsNullOrEmpty(sb.path) || !File.Exists(sb.path); shadersBuildInfo.Add(sb); EditorUtility.SetDirty(shadersBuildInfo); } else if (!sb.includeInBuild) { skipCompilation = true; } int count = shaderCompilerData.Count; for (int i = 0; i < count; ++i) { ShaderKeywordSet ks = shaderCompilerData[i].shaderKeywordSet; ShaderKeyword[] shaderKeywords = ks.GetShaderKeywords(); // Check if variants are allowed if (shaderKeywords.Length > 0 && sb.variants != null && sb.variants.Count > 0) { bool includedVariant = false; foreach (var variant in sb.variants) { if (variant.Same(shader, shaderKeywords)) { includedVariant = true; break; } } if (!includedVariant) { shaderCompilerData.RemoveAt(i); count--; i--; continue; // for } } // Check if keywords are allowed foreach (ShaderKeyword kw in shaderKeywords) { #if UNITY_2021_2_OR_NEWER string kname = kw.name; #elif UNITY_2019_3_OR_NEWER string kname = ShaderKeyword.GetKeywordName(shader, kw); #elif UNITY_2018_4_OR_NEWER string kname = kw.GetKeywordName(); #else string kname = kw.GetName(); #endif if (string.IsNullOrEmpty(kname)) { continue; } if (!sb.KeywordsIsIncluded(kname)) { shaderCompilerData.RemoveAt(i); count--; i--; break; } else { EditorUtility.SetDirty(shadersBuildInfo); } } } if (skipCompilation) { shaderCompilerData.Clear(); return; } } catch (Exception ex) { Debug.LogWarning("Shader Control detected an error during compilation of one shader: " + ex.ToString()); } } } }