void DrawBuildGUI() { GUILayout.Box(new GUIContent("This tab shows all shaders compiled in your last build.\nHere you can exclude any number of shaders or keywords from future compilations. No file is modified, only excluded from the build.\nIf you have exceeded the maximum allowed keywords in your project, use the <color=orange><b>Project View</b></color> tab to remove shaders or disable any unwanted keyword from the project."), titleStyle); EditorGUILayout.Separator(); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button(new GUIContent("Quick Build", "Forces a quick compilation to extract all shaders and keywords included in the build."))) { EditorUtility.DisplayDialog("Ready for the Build!", "Now make a build as normal (select 'File -> Build Settings -> Build').\n\nShader Control will detect the shaders and keywords from the build process and list that information here.\n\nNote: in order to make this special build faster, shaders won't be compiled in this build.", "Ok"); SetEditorPrefBool("QUICK_BUILD", true); nextQuickBuild = true; ClearBuildData(); } if (GUILayout.Button("Help", GUILayout.Width(40))) { ShowHelpWindowBuildView(); } EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); if (nextQuickBuild) { EditorGUILayout.HelpBox("Shader Control is ready to collect data during the next build.", MessageType.Info); } int shadersCount = shadersBuildInfo == null || shadersBuildInfo.shaders == null ? 0 : shadersBuildInfo.shaders.Count; if (!nextQuickBuild) { EditorGUILayout.LabelField("Last build: " + ((shadersBuildInfo.creationDateTicks != 0) ? shadersBuildInfo.creationDateString : "no data yet. Click 'Quick Build' for more details."), EditorStyles.boldLabel); } if (shadersBuildInfo != null && shadersBuildInfo.requiresBuild) { EditorGUILayout.HelpBox("Project shaders have been modified. Do a 'Quick Build' again to ensure the data shown in this tab is accurate.", MessageType.Warning); } if (shadersCount > 0) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("View", GUILayout.Width(90)); EditorGUI.BeginChangeCheck(); shadersBuildInfo.viewType = (BuildViewShaderOption)GUILayout.SelectionGrid((int)shadersBuildInfo.viewType, viewShaderTexts, 3); if (EditorGUI.EndChangeCheck()) { EditorUtility.SetDirty(shadersBuildInfo); RefreshBuildStats(true); } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Sort By", GUILayout.Width(90)); EditorGUI.BeginChangeCheck(); shadersBuildInfo.sortType = (BuildViewSortType)EditorGUILayout.EnumPopup(shadersBuildInfo.sortType); if (EditorGUI.EndChangeCheck()) { if (shadersBuildInfo != null) { shadersBuildInfo.Resort(); } EditorUtility.SetDirty(shadersBuildInfo); GUIUtility.ExitGUI(); return; } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Shader Name", GUILayout.Width(90)); EditorGUI.BeginChangeCheck(); buildShaderNameFilter = EditorGUILayout.TextField(buildShaderNameFilter); if (GUILayout.Button(new GUIContent("Clear", "Clear filter."), EditorStyles.miniButton, GUILayout.Width(60))) { buildShaderNameFilter = ""; GUIUtility.keyboardControl = 0; } EditorGUILayout.EndHorizontal(); if (EditorGUI.EndChangeCheck()) { RefreshBuildStats(true); } EditorGUI.BeginChangeCheck(); if (shadersBuildInfo.sortType != BuildViewSortType.Keyword) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Keywords >=", GUILayout.Width(90)); minimumKeywordCount = EditorGUILayout.IntSlider(minimumKeywordCount, 0, maxBuildKeywordsCountFound); EditorGUILayout.EndHorizontal(); } EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Keyword Filter", GUILayout.Width(90)); keywordFilter = EditorGUILayout.TextField(keywordFilter); if (GUILayout.Button(new GUIContent("Clear", "Clear filter."), EditorStyles.miniButton, GUILayout.Width(60))) { keywordFilter = ""; GUIUtility.keyboardControl = 0; } EditorGUILayout.EndHorizontal(); if (EditorGUI.EndChangeCheck()) { RefreshBuildStats(true); } EditorGUILayout.Separator(); if (totalBuildShaders == 0 || totalBuildIncludedShaders == 0 || totalBuildKeywords == 0 || (totalBuildKeywords == totalBuildIncludedKeywords && totalBuildShaders == totalBuildIncludedShaders)) { EditorGUILayout.HelpBox("Total Shaders: " + totalBuildShaders + " Shaders Using Keywords: " + totalBuildShadersWithKeywords + "\nTotal Unique Keywords: " + totalBuildKeywords, MessageType.Info); } else { int shadersPerc = totalBuildIncludedShaders * 100 / totalBuildShaders; int shadersWithKeywordsPerc = totalBuildIncludedShadersWithKeywords * 100 / totalBuildIncludedShaders; int keywordsPerc = totalBuildIncludedKeywords * 100 / totalBuildKeywords; EditorGUILayout.HelpBox("Total Shaders: " + totalBuildIncludedShaders + " of " + totalBuildShaders + " (" + shadersPerc + "%" + " Shaders Using Keywords: " + totalBuildIncludedShadersWithKeywords + " of " + totalBuildShadersWithKeywords + " (" + shadersWithKeywordsPerc + "%)\nTotal Unique Keywords: " + totalBuildIncludedKeywords + " of " + totalBuildKeywords + " (" + keywordsPerc.ToString() + "%)", MessageType.Info); } EditorGUILayout.Separator(); scrollViewPosProject = EditorGUILayout.BeginScrollView(scrollViewPosProject); bool requireUpdate = false; if (shadersBuildInfo.sortType == BuildViewSortType.Keyword) { if (buildKeywordView != null) { int kvCount = buildKeywordView.Count; for (int s = 0; s < kvCount; s++) { BuildKeywordView kwv = buildKeywordView[s]; string keyword = kwv.keyword; if (!string.IsNullOrEmpty(keywordFilter) && keyword.IndexOf(keywordFilter, StringComparison.InvariantCultureIgnoreCase) < 0) { continue; } EditorGUILayout.BeginHorizontal(); kwv.foldout = EditorGUILayout.Foldout(kwv.foldout, new GUIContent("Keyword #" + (s + 1) + " <b>" + kwv.keyword + "</b> found in " + kwv.shaders.Count + " shader(s)"), foldoutRTF); if (!kwv.isInternal && GUILayout.Button("Show In Project View", EditorStyles.miniButton, GUILayout.Width(160))) { sortType = SortType.EnabledKeywordsCount; projectShaderNameFilter = ""; keywordFilter = kwv.keyword; scanAllShaders = true; if (shaders == null) { ScanProject(); } viewMode = ViewMode.Project; GUIUtility.ExitGUI(); } EditorGUILayout.EndHorizontal(); if (kwv.foldout) { int kvShadersCount = kwv.shaders.Count; for (int m = 0; m < kvShadersCount; m++) { ShaderBuildInfo sb = kwv.shaders[m]; EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("", GUILayout.Width(30)); EditorGUILayout.LabelField(shaderIcon, GUILayout.Width(18)); EditorGUILayout.LabelField(sb.name); if (sb.isInternal) { GUILayout.Label("(Internal Shader)"); } else { if (GUILayout.Button("Locate", EditorStyles.miniButton, GUILayout.Width(80))) { PingShader(sb.name); } if (GUILayout.Button("Show In Project View", EditorStyles.miniButton, GUILayout.Width(160))) { projectShaderNameFilter = sb.simpleName; keywordFilter = ""; scanAllShaders = true; PingShader(sb.name); if (shaders == null) { ScanProject(); } viewMode = ViewMode.Project; GUIUtility.ExitGUI(); } } EditorGUILayout.EndHorizontal(); } } } } } else { for (int k = 0; k < shadersCount; k++) { ShaderBuildInfo sb = shadersBuildInfo.shaders[k]; int kwCount = sb.keywords == null ? 0 : sb.keywords.Count; if (kwCount < minimumKeywordCount) { continue; } if (shadersBuildInfo.viewType == BuildViewShaderOption.ProjectShaders && sb.isInternal) { continue; } if (shadersBuildInfo.viewType == BuildViewShaderOption.UnityInternalShaders && !sb.isInternal) { continue; } if (!string.IsNullOrEmpty(keywordFilter) && !sb.ContainsKeyword(keywordFilter, false)) { continue; } if (!string.IsNullOrEmpty(buildShaderNameFilter) && sb.name.IndexOf(buildShaderNameFilter, StringComparison.InvariantCultureIgnoreCase) < 0) { continue; } GUI.enabled = sb.includeInBuild; EditorGUILayout.BeginHorizontal(); string shaderName = (sb.isInternal && shadersBuildInfo.viewType != BuildViewShaderOption.UnityInternalShaders) ? sb.name + " (internal)" : sb.name; sb.isExpanded = EditorGUILayout.Foldout(sb.isExpanded, shaderName + " (" + kwCount + " keyword" + (kwCount != 1 ? "s)" : ")"), sb.isInternal ? foldoutDim : foldoutNormal); GUILayout.FlexibleSpace(); GUI.enabled = true; if (sb.name != "Standard") { EditorGUI.BeginChangeCheck(); sb.includeInBuild = EditorGUILayout.ToggleLeft("Include", sb.includeInBuild, GUILayout.Width(90)); if (EditorGUI.EndChangeCheck()) { requireUpdate = true; } } EditorGUILayout.EndHorizontal(); if (sb.isExpanded) { GUI.enabled = sb.includeInBuild; EditorGUI.indentLevel++; if (kwCount == 0) { EditorGUILayout.LabelField("No keywords."); } else { if (!sb.isInternal) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("", GUILayout.Width(15)); if (GUILayout.Button("Locate", EditorStyles.miniButton, GUILayout.Width(80))) { PingShader(sb.name); } if (!sb.isInternal && GUILayout.Button("Show In Project View", EditorStyles.miniButton, GUILayout.Width(160))) { projectShaderNameFilter = sb.simpleName; scanAllShaders = true; PingShader(sb.name); if (shaders == null) { ScanProject(); } viewMode = ViewMode.Project; GUIUtility.ExitGUI(); } EditorGUILayout.EndHorizontal(); } for (int j = 0; j < kwCount; j++) { KeywordBuildSettings kw = sb.keywords[j]; EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(kw.keyword); GUILayout.FlexibleSpace(); EditorGUI.BeginChangeCheck(); kw.includeInBuild = EditorGUILayout.ToggleLeft("Include", kw.includeInBuild, GUILayout.Width(90)); if (EditorGUI.EndChangeCheck()) { requireUpdate = true; } EditorGUILayout.EndHorizontal(); } } EditorGUI.indentLevel--; } GUI.enabled = true; } } EditorGUILayout.EndScrollView(); if (requireUpdate) { RefreshBuildStats(true); EditorUtility.SetDirty(shadersBuildInfo); AssetDatabase.SaveAssets(); } } }
void RefreshBuildStats(bool quick) { issueRefresh = 1; nextQuickBuild = GetEditorPrefBool("QUICK_BUILD", false); shadersBuildInfo = ShaderDebugBuildProcessor.CheckShadersBuildStore(shadersBuildInfo); totalBuildKeywords = totalBuildIncludedKeywords = totalBuildShadersWithKeywords = totalBuildShaders = totalBuildIncludedShaders = totalBuildIncludedShadersWithKeywords = 0; shadersBuildInfo = Resources.Load <ShadersBuildInfo>("BuiltShaders"); if (shadersBuildInfo == null || shadersBuildInfo.shaders == null) { return; } if (uniqueBuildKeywords == null) { uniqueBuildKeywords = new Dictionary <string, List <ShaderBuildInfo> >(); } else { uniqueBuildKeywords.Clear(); } if (uniqueIncludedBuildKeywords == null) { uniqueIncludedBuildKeywords = new Dictionary <string, List <ShaderBuildInfo> >(); } else { uniqueIncludedBuildKeywords.Clear(); } int count = shadersBuildInfo.shaders.Count; totalBuildShaders = 0; maxBuildKeywordsCountFound = 0; for (int k = 0; k < count; k++) { ShaderBuildInfo sb = shadersBuildInfo.shaders[k]; int kwCount = sb.keywords != null ? sb.keywords.Count : 0; if (shadersBuildInfo.sortType != BuildViewSortType.Keyword) { if (minimumKeywordCount > 0 && kwCount < minimumKeywordCount) { continue; } if (!string.IsNullOrEmpty(keywordFilter) && !sb.ContainsKeyword(keywordFilter, false)) { continue; } } if (shadersBuildInfo.viewType == BuildViewShaderOption.ProjectShaders && sb.isInternal) { continue; } if (shadersBuildInfo.viewType == BuildViewShaderOption.UnityInternalShaders && !sb.isInternal) { continue; } if (!string.IsNullOrEmpty(buildShaderNameFilter) && sb.name.IndexOf(buildShaderNameFilter, StringComparison.InvariantCultureIgnoreCase) < 0) { continue; } totalBuildShaders++; // Check shaders exist if (!quick && Shader.Find(sb.name) == null) { shadersBuildInfo.shaders.RemoveAt(k); k--; totalBuildShaders--; count--; continue; } if (sb.includeInBuild) { totalBuildIncludedShaders++; } if (kwCount > 0) { if (kwCount > maxBuildKeywordsCountFound) { maxBuildKeywordsCountFound = kwCount; } //totalBuildKeywords += kwCount; totalBuildShadersWithKeywords++; if (sb.includeInBuild) { totalBuildIncludedShadersWithKeywords++; for (int j = 0; j < kwCount; j++) { List <ShaderBuildInfo> shaderList; if (!uniqueBuildKeywords.TryGetValue(sb.keywords[j].keyword, out shaderList)) { totalBuildKeywords++; shaderList = new List <ShaderBuildInfo>(); uniqueBuildKeywords[sb.keywords[j].keyword] = shaderList; } shaderList.Add(sb); if (sb.keywords[j].includeInBuild) { List <ShaderBuildInfo> includedList; if (!uniqueIncludedBuildKeywords.TryGetValue(sb.keywords[j].keyword, out includedList)) { totalBuildIncludedKeywords++; includedList = new List <ShaderBuildInfo>(); uniqueIncludedBuildKeywords[sb.keywords[j].keyword] = includedList; } includedList.Add(sb); } } } } } if (buildKeywordView == null) { buildKeywordView = new List <BuildKeywordView>(); } else { buildKeywordView.Clear(); } foreach (KeyValuePair <string, List <ShaderBuildInfo> > kvp in uniqueBuildKeywords) { BuildKeywordView kv = new BuildKeywordView { keyword = kvp.Key, shaders = kvp.Value }; buildKeywordView.Add(kv); } buildKeywordView.Sort(delegate(BuildKeywordView x, BuildKeywordView y) { return(y.shaders.Count.CompareTo(x.shaders.Count)); }); // Annotate which keywords are used in project int bkwCount = buildKeywordView.Count; for (int k = 0; k < bkwCount; k++) { BuildKeywordView bkv = buildKeywordView[k]; bool isInternal = true; int shadersCount = bkv.shaders.Count; for (int j = 0; j < shadersCount; j++) { if (!bkv.shaders[j].isInternal) { isInternal = false; break; } } bkv.isInternal = isInternal; } UpdateProjectStats(); }