SCWindow.Build.GUI.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. /*
  2. Shader Control - (C) Copyright 2016-2019 Ramiro Oliva (Kronnect)
  3. */
  4. using UnityEngine;
  5. using UnityEditor;
  6. using System;
  7. using System.Text;
  8. namespace ShaderControl {
  9. public enum BuildViewSortType {
  10. ShaderName = 0,
  11. ShaderKeywordCount = 1,
  12. Keyword = 2
  13. }
  14. public partial class SCWindow : EditorWindow {
  15. string buildShaderNameFilter;
  16. StringBuilder sb = new StringBuilder();
  17. void DrawBuildGUI() {
  18. 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 <b>Project View</b> tab to remove shaders or disable any unwanted keyword from the project."), titleStyle, GUILayout.ExpandWidth(true));
  19. EditorGUILayout.Separator();
  20. EditorGUILayout.BeginHorizontal();
  21. if (GUILayout.Button(new GUIContent("Quick Build", "Forces a quick compilation to extract all shaders and keywords included in the build."))) {
  22. EditorUtility.DisplayDialog("Ready to analyze!", "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\nImportant Note!\nTo make this special build faster, shaders won't be compiled (they will show in pink in the build). This is normal. To create a normal build, just build the project again without clicking 'Quick Build'.", "Ok");
  23. SetEditorPrefBool("QUICK_BUILD", true);
  24. nextQuickBuild = true;
  25. ClearBuildData();
  26. }
  27. if (GUILayout.Button("Help", GUILayout.Width(40))) {
  28. ShowHelpWindowBuildView();
  29. }
  30. EditorGUILayout.EndHorizontal();
  31. EditorGUILayout.EndVertical();
  32. if (nextQuickBuild) {
  33. EditorGUILayout.HelpBox("Shader Control is ready to collect data during the next build.", MessageType.Info);
  34. }
  35. int shadersCount = shadersBuildInfo == null || shadersBuildInfo.shaders == null ? 0 : shadersBuildInfo.shaders.Count;
  36. if (shadersBuildInfo != null) {
  37. if (!nextQuickBuild) {
  38. EditorGUILayout.LabelField("Last build: " + ((shadersBuildInfo.creationDateTicks != 0) ? shadersBuildInfo.creationDateString : "no data yet. Click 'Quick Build' for more details."), EditorStyles.boldLabel);
  39. }
  40. if (shadersBuildInfo.requiresBuild) {
  41. EditorGUILayout.HelpBox("Project shaders have been modified. Do a 'Quick Build' again to ensure the data shown in this tab is accurate.", MessageType.Warning);
  42. }
  43. }
  44. if (shadersCount == 0) return;
  45. if (totalBuildShaders == 0 || totalBuildIncludedShaders == 0 || totalBuildKeywords == 0 || (totalBuildKeywords == totalBuildIncludedKeywords && totalBuildShaders == totalBuildIncludedShaders)) {
  46. EditorGUILayout.HelpBox("Total Compiled Shaders: " + totalBuildShaders + " Shaders Using Keywords: " + totalBuildShadersWithKeywords + "\nTotal Unique Keywords: " + totalBuildKeywords, MessageType.Info);
  47. } else {
  48. int shadersPerc = totalBuildIncludedShaders * 100 / totalBuildShaders;
  49. int shadersWithKeywordsPerc = totalBuildIncludedShadersWithKeywords * 100 / totalBuildIncludedShaders;
  50. int keywordsPerc = totalBuildIncludedKeywords * 100 / totalBuildKeywords;
  51. EditorGUILayout.HelpBox("Total Compiled Shaders: " + totalBuildIncludedShaders + " of " + totalBuildShaders + " (" + shadersPerc + "%" + " Shaders Using Keywords: " + totalBuildIncludedShadersWithKeywords + " of " + totalBuildShadersWithKeywords + " (" + shadersWithKeywordsPerc + "%)\nTotal Unique Keywords: " + totalBuildIncludedKeywords + " of " + totalBuildKeywords + " (" + keywordsPerc.ToString() + "%)", MessageType.Info);
  52. }
  53. EditorGUILayout.Separator();
  54. EditorGUILayout.BeginHorizontal();
  55. EditorGUILayout.LabelField("Sort By", GUILayout.Width(100));
  56. EditorGUI.BeginChangeCheck();
  57. shadersBuildInfo.sortType = (BuildViewSortType)EditorGUILayout.EnumPopup(shadersBuildInfo.sortType);
  58. if (EditorGUI.EndChangeCheck()) {
  59. if (shadersBuildInfo != null) {
  60. shadersBuildInfo.Resort();
  61. }
  62. EditorUtility.SetDirty(shadersBuildInfo);
  63. GUIUtility.ExitGUI();
  64. return;
  65. }
  66. EditorGUILayout.EndHorizontal();
  67. EditorGUILayout.BeginHorizontal();
  68. EditorGUILayout.LabelField("Shader Name", GUILayout.Width(100));
  69. buildShaderNameFilter = EditorGUILayout.TextField(buildShaderNameFilter);
  70. if (GUILayout.Button(new GUIContent("Clear", "Clear filter."), EditorStyles.miniButton, GUILayout.Width(60))) {
  71. buildShaderNameFilter = "";
  72. GUIUtility.keyboardControl = 0;
  73. }
  74. EditorGUILayout.EndHorizontal();
  75. if (shadersBuildInfo.sortType != BuildViewSortType.Keyword) {
  76. EditorGUILayout.BeginHorizontal();
  77. EditorGUILayout.LabelField("Keywords >=", GUILayout.Width(100));
  78. minimumKeywordCount = EditorGUILayout.IntSlider(minimumKeywordCount, 0, maxBuildKeywordsCountFound);
  79. EditorGUILayout.EndHorizontal();
  80. }
  81. EditorGUILayout.BeginHorizontal();
  82. EditorGUILayout.LabelField("Keyword Filter", GUILayout.Width(100));
  83. keywordFilter = EditorGUILayout.TextField(keywordFilter);
  84. if (GUILayout.Button(new GUIContent("Clear", "Clear filter."), EditorStyles.miniButton, GUILayout.Width(60))) {
  85. keywordFilter = "";
  86. GUIUtility.keyboardControl = 0;
  87. }
  88. EditorGUILayout.EndHorizontal();
  89. if (shadersBuildInfo.sortType != BuildViewSortType.Keyword) {
  90. shadersBuildInfo.hideReadOnlyShaders = EditorGUILayout.ToggleLeft("Hide read-only/internal shaders", shadersBuildInfo.hideReadOnlyShaders);
  91. }
  92. EditorGUILayout.Separator();
  93. scrollViewPosProject = EditorGUILayout.BeginScrollView(scrollViewPosProject);
  94. bool requireUpdate = false;
  95. bool needsTitle = true;
  96. if (shadersBuildInfo.sortType == BuildViewSortType.Keyword) {
  97. if (buildKeywordView != null) {
  98. int kvCount = buildKeywordView.Count;
  99. for (int s = 0; s < kvCount; s++) {
  100. BuildKeywordView kwv = buildKeywordView[s];
  101. string keyword = kwv.keyword;
  102. if (!string.IsNullOrEmpty(keywordFilter) && keyword.IndexOf(keywordFilter, StringComparison.InvariantCultureIgnoreCase) < 0)
  103. continue;
  104. if (needsTitle) {
  105. needsTitle = false;
  106. GUILayout.Label("Used keywords:");
  107. }
  108. int kvShadersCount = kwv.shaders.Count;
  109. sb.Length = 0;
  110. sb.Append("Keyword #");
  111. sb.Append(s + 1);
  112. sb.Append(" <b>");
  113. sb.Append(kwv.keyword);
  114. sb.Append("</b> found in ");
  115. sb.Append(kvShadersCount);
  116. sb.Append(" shader(s)");
  117. EditorGUILayout.BeginHorizontal();
  118. kwv.foldout = EditorGUILayout.Foldout(kwv.foldout, new GUIContent(sb.ToString()), foldoutRTF);
  119. if (!kwv.isInternal && GUILayout.Button("Show In Project View", EditorStyles.miniButton, GUILayout.Width(160))) {
  120. sortType = SortType.EnabledKeywordsCount;
  121. projectShaderNameFilter = "";
  122. keywordFilter = kwv.keyword;
  123. keywordScopeFilter = KeywordScopeFilter.Any;
  124. pragmaTypeFilter = PragmaTypeFilter.Any;
  125. scanAllShaders = true;
  126. if (shaders == null) ScanProject();
  127. viewMode = ViewMode.Project;
  128. GUIUtility.ExitGUI();
  129. }
  130. EditorGUILayout.EndHorizontal();
  131. if (kwv.foldout) {
  132. for (int m = 0; m < kvShadersCount; m++) {
  133. ShaderBuildInfo sb = kwv.shaders[m];
  134. EditorGUILayout.BeginHorizontal();
  135. EditorGUILayout.LabelField("", GUILayout.Width(30));
  136. EditorGUILayout.LabelField(shaderIcon, GUILayout.Width(18));
  137. EditorGUILayout.LabelField(sb.name);
  138. if (sb.isInternal) {
  139. GUILayout.Label("(Internal Shader)");
  140. } else {
  141. if (GUILayout.Button("Locate", EditorStyles.miniButton, GUILayout.Width(80))) {
  142. PingShader(sb.name);
  143. }
  144. if (GUILayout.Button("Show In Project View", EditorStyles.miniButton, GUILayout.Width(160))) {
  145. projectShaderNameFilter = sb.simpleName;
  146. keywordFilter = "";
  147. keywordScopeFilter = KeywordScopeFilter.Any;
  148. pragmaTypeFilter = PragmaTypeFilter.Any;
  149. scanAllShaders = true;
  150. PingShader(sb.name);
  151. if (shaders == null) ScanProject();
  152. viewMode = ViewMode.Project;
  153. GUIUtility.ExitGUI();
  154. }
  155. }
  156. EditorGUILayout.EndHorizontal();
  157. }
  158. }
  159. }
  160. }
  161. } else {
  162. for (int k = 0; k < shadersCount; k++) {
  163. ShaderBuildInfo sb = shadersBuildInfo.shaders[k];
  164. int kwCount = sb.keywords == null ? 0 : sb.keywords.Count;
  165. if (kwCount < minimumKeywordCount && minimumKeywordCount > 0) continue;
  166. if ((sb.isReadOnly || sb.isInternal) && shadersBuildInfo.hideReadOnlyShaders) continue;
  167. if (!string.IsNullOrEmpty(keywordFilter) && !sb.ContainsKeyword(keywordFilter, false))
  168. continue;
  169. if (!string.IsNullOrEmpty(buildShaderNameFilter) && sb.name.IndexOf(buildShaderNameFilter, StringComparison.InvariantCultureIgnoreCase) < 0) continue;
  170. if (needsTitle) {
  171. needsTitle = false;
  172. GUILayout.Label("Compiled shaders:");
  173. }
  174. GUI.enabled = sb.includeInBuild;
  175. EditorGUILayout.BeginHorizontal();
  176. string shaderName = sb.name;
  177. if (sb.isInternal) shaderName += " (internal, ";
  178. else if (sb.isReadOnly) shaderName += " (read-only, ";
  179. else shaderName += " (";
  180. sb.isExpanded = EditorGUILayout.Foldout(sb.isExpanded, shaderName + kwCount + " keyword" + (kwCount != 1 ? "s)" : ")"), sb.isInternal ? foldoutDim : foldoutNormal);
  181. GUILayout.FlexibleSpace();
  182. GUI.enabled = true;
  183. if (sb.name != "Standard") {
  184. EditorGUI.BeginChangeCheck();
  185. sb.includeInBuild = EditorGUILayout.ToggleLeft("Include", sb.includeInBuild, GUILayout.Width(90));
  186. if (EditorGUI.EndChangeCheck()) {
  187. requireUpdate = true;
  188. }
  189. }
  190. EditorGUILayout.EndHorizontal();
  191. if (sb.isExpanded) {
  192. GUI.enabled = sb.includeInBuild;
  193. EditorGUI.indentLevel++;
  194. if (kwCount == 0) {
  195. EditorGUILayout.LabelField("No keywords.");
  196. } else {
  197. if (!sb.isInternal) {
  198. EditorGUILayout.BeginHorizontal();
  199. EditorGUILayout.LabelField("", GUILayout.Width(15));
  200. if (GUILayout.Button("Locate", EditorStyles.miniButton, GUILayout.Width(80))) {
  201. PingShader(sb.name);
  202. }
  203. if (!sb.isInternal && GUILayout.Button("Show In Project View", EditorStyles.miniButton, GUILayout.Width(160))) {
  204. projectShaderNameFilter = sb.simpleName;
  205. keywordScopeFilter = KeywordScopeFilter.Any;
  206. pragmaTypeFilter = PragmaTypeFilter.Any;
  207. scanAllShaders = true;
  208. PingShader(sb.name);
  209. if (shaders == null) ScanProject();
  210. viewMode = ViewMode.Project;
  211. GUIUtility.ExitGUI();
  212. }
  213. EditorGUILayout.EndHorizontal();
  214. }
  215. for (int j = 0; j < kwCount; j++) {
  216. KeywordBuildSettings kw = sb.keywords[j];
  217. EditorGUILayout.BeginHorizontal();
  218. EditorGUILayout.LabelField(kw.keyword);
  219. GUILayout.FlexibleSpace();
  220. EditorGUI.BeginChangeCheck();
  221. kw.includeInBuild = EditorGUILayout.ToggleLeft("Include", kw.includeInBuild, GUILayout.Width(90));
  222. if (EditorGUI.EndChangeCheck()) {
  223. requireUpdate = true;
  224. }
  225. EditorGUILayout.EndHorizontal();
  226. }
  227. }
  228. EditorGUILayout.BeginHorizontal();
  229. GUILayout.Space(20);
  230. if (GUILayout.Button("Advanced...", GUILayout.Width(120))) {
  231. SCShader projectShader = GetShaderByName(sb.name);
  232. SCWindowAdvanced.ShowWindow(sb, projectShader);
  233. }
  234. int variantsCount = sb.variants != null ? sb.variants.Count : 0;
  235. if (variantsCount > 0) {
  236. GUILayout.Label("(Only building " + variantsCount + " variants)");
  237. }
  238. EditorGUILayout.EndHorizontal();
  239. EditorGUI.indentLevel--;
  240. }
  241. GUI.enabled = true;
  242. }
  243. }
  244. EditorGUILayout.EndScrollView();
  245. if (requireUpdate) {
  246. RefreshBuildStats(true);
  247. EditorUtility.SetDirty(shadersBuildInfo);
  248. AssetDatabase.SaveAssets();
  249. }
  250. }
  251. }
  252. }