No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

KeywordUtil.cs 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using UnityEditor.ShaderGraph.Drawing;
  6. using UnityEngine;
  7. using UnityEditor.ShaderGraph.Internal;
  8. namespace UnityEditor.ShaderGraph
  9. {
  10. static class BuiltinKeyword
  11. {
  12. [BuiltinKeyword]
  13. public static KeywordDescriptor QualityKeyword()
  14. {
  15. return new KeywordDescriptor()
  16. {
  17. displayName = "Material Quality",
  18. referenceName = "MATERIAL_QUALITY",
  19. type = KeywordType.Enum,
  20. definition = KeywordDefinition.MultiCompile,
  21. scope = KeywordScope.Global,
  22. value = 0,
  23. entries = new KeywordEntry[]
  24. {
  25. new KeywordEntry("High", "HIGH"),
  26. new KeywordEntry("Medium", "MEDIUM"),
  27. new KeywordEntry("Low", "LOW"),
  28. },
  29. stages = KeywordShaderStage.All,
  30. };
  31. }
  32. }
  33. static class KeywordUtil
  34. {
  35. public static IEnumerable<KeywordDescriptor> GetBuiltinKeywordDescriptors() =>
  36. TypeCache.GetMethodsWithAttribute<BuiltinKeywordAttribute>()
  37. .Where(method => method.IsStatic && method.ReturnType == typeof(KeywordDescriptor))
  38. .Select(method =>
  39. (KeywordDescriptor)method.Invoke(null, new object[0] { }));
  40. public static ConcreteSlotValueType ToConcreteSlotValueType(this KeywordType keywordType)
  41. {
  42. switch (keywordType)
  43. {
  44. case KeywordType.Boolean:
  45. return ConcreteSlotValueType.Boolean;
  46. case KeywordType.Enum:
  47. return ConcreteSlotValueType.Vector1;
  48. default:
  49. throw new ArgumentOutOfRangeException();
  50. }
  51. }
  52. public static string ToDeclarationSuffix(this KeywordScope scope)
  53. {
  54. switch (scope)
  55. {
  56. case KeywordScope.Local:
  57. return "_local";
  58. default:
  59. return string.Empty;
  60. }
  61. }
  62. public static string ToDeclarationString(this KeywordDefinition keywordDefinition)
  63. {
  64. switch (keywordDefinition)
  65. {
  66. case KeywordDefinition.MultiCompile:
  67. return "multi_compile";
  68. case KeywordDefinition.ShaderFeature:
  69. return "shader_feature";
  70. default:
  71. return string.Empty;
  72. }
  73. }
  74. static void GenerateKeywordPragmaStrings(
  75. string keywordReferenceName,
  76. KeywordDefinition keywordDefinition,
  77. KeywordScope keywordScope,
  78. KeywordShaderStage keywordStages,
  79. string keywordVariantsString,
  80. Action<string> PragmaStringAction)
  81. {
  82. string definitionString = keywordDefinition.ToDeclarationString();
  83. string scopeString = keywordScope.ToDeclarationSuffix();
  84. // check the active shader stages
  85. if ((keywordStages == KeywordShaderStage.All) || (keywordStages == 0)) // 0 is a default, so assume that means ALL
  86. {
  87. PragmaStringAction($"#pragma {definitionString}{scopeString} {keywordVariantsString}");
  88. }
  89. else
  90. {
  91. // have to process each stage separately
  92. for (int shaderStage = (int)KeywordShaderStage.Vertex; shaderStage <= (int)keywordStages; shaderStage = shaderStage * 2)
  93. {
  94. if (((int)keywordStages & shaderStage) != 0)
  95. {
  96. var keywordStage = (KeywordShaderStage)shaderStage;
  97. var stageString = keywordStage.ToKeywordStagesString();
  98. PragmaStringAction($"#pragma {definitionString}{scopeString}{stageString} {keywordVariantsString}");
  99. }
  100. }
  101. }
  102. }
  103. public static void GenerateEnumKeywordPragmaStrings(
  104. string keywordReferenceName,
  105. KeywordDefinition keywordDefinition,
  106. KeywordScope keywordScope,
  107. KeywordShaderStage keywordStages,
  108. IEnumerable<KeywordEntry> keywordEntries,
  109. Action<string> pragmaStringAction)
  110. {
  111. if (keywordDefinition != KeywordDefinition.Predefined)
  112. {
  113. var entryStrings = keywordEntries.Select(x => string.IsNullOrEmpty(x.referenceName) ? "_" : $"{keywordReferenceName}_{x.referenceName}");
  114. string variantsString = string.Join(" ", entryStrings);
  115. GenerateKeywordPragmaStrings(keywordReferenceName, keywordDefinition, keywordScope, keywordStages, variantsString, pragmaStringAction);
  116. }
  117. }
  118. public static void GenerateBooleanKeywordPragmaStrings(
  119. string keywordReferenceName,
  120. KeywordDefinition keywordDefinition,
  121. KeywordScope keywordScope,
  122. KeywordShaderStage keywordStages,
  123. Action<string> pragmaStringAction)
  124. {
  125. if (keywordDefinition != KeywordDefinition.Predefined)
  126. {
  127. string variantsString = $"_ {keywordReferenceName}";
  128. GenerateKeywordPragmaStrings(keywordReferenceName, keywordDefinition, keywordScope, keywordStages, variantsString, pragmaStringAction);
  129. }
  130. }
  131. public static string ToKeywordStagesString(this KeywordShaderStage stages)
  132. {
  133. string outString = "";
  134. if (stages == KeywordShaderStage.All)
  135. return outString;
  136. if (stages == KeywordShaderStage.Vertex)
  137. outString += "_vertex";
  138. if (stages == KeywordShaderStage.Fragment)
  139. outString += "_fragment";
  140. if (stages == KeywordShaderStage.Geometry)
  141. outString += "_geometry";
  142. if (stages == KeywordShaderStage.Hull)
  143. outString += "_hull";
  144. if (stages == KeywordShaderStage.Domain)
  145. outString += "_domain";
  146. if (stages == KeywordShaderStage.RayTracing)
  147. outString += "_raytracing";
  148. return outString;
  149. }
  150. public static string ToDefineString(this KeywordDescriptor keyword, int value)
  151. {
  152. switch (keyword.type)
  153. {
  154. case KeywordType.Boolean:
  155. return value == 1 ? $"#define {keyword.referenceName} 1" : string.Empty;
  156. case KeywordType.Enum:
  157. return $"#define {keyword.referenceName}_{keyword.entries[value].referenceName}";
  158. default:
  159. throw new ArgumentOutOfRangeException();
  160. }
  161. }
  162. public static string GetKeywordPermutationSetConditional(List<int> permutationSet)
  163. {
  164. StringBuilder sb = new StringBuilder();
  165. sb.Append("#if ");
  166. for (int i = 0; i < permutationSet.Count; i++)
  167. {
  168. // Subsequent permutation predicates require ||
  169. if (i != 0)
  170. sb.Append(" || ");
  171. // Append permutation
  172. sb.Append($"defined(KEYWORD_PERMUTATION_{permutationSet[i]})");
  173. }
  174. return sb.ToString();
  175. }
  176. public static string GetKeywordPermutationConditional(int permutation)
  177. {
  178. return $"#if defined(KEYWORD_PERMUTATION_{permutation})";
  179. }
  180. public static void GetKeywordPermutationDeclarations(ShaderStringBuilder sb, List<List<KeyValuePair<ShaderKeyword, int>>> permutations)
  181. {
  182. if (permutations.Count == 0)
  183. return;
  184. for (int p = 0; p < permutations.Count; p++)
  185. {
  186. // ShaderStringBuilder.Append doesnt apply indentation
  187. sb.TryAppendIndentation();
  188. // Append correct if
  189. bool isLast = false;
  190. if (p == 0)
  191. {
  192. sb.Append("#if ");
  193. }
  194. else if (p == permutations.Count - 1)
  195. {
  196. sb.Append("#else");
  197. isLast = true;
  198. }
  199. else
  200. {
  201. sb.Append("#elif ");
  202. }
  203. // Last permutation is always #else
  204. if (!isLast)
  205. {
  206. // Track whether && is required
  207. bool appendAnd = false;
  208. // Iterate all keywords that are part of the permutation
  209. for (int i = 0; i < permutations[p].Count; i++)
  210. {
  211. // When previous keyword was inserted subsequent requires &&
  212. string and = appendAnd ? " && " : string.Empty;
  213. switch (permutations[p][i].Key.keywordType)
  214. {
  215. case KeywordType.Enum:
  216. {
  217. sb.Append($"{and}defined({permutations[p][i].Key.referenceName}_{permutations[p][i].Key.entries[permutations[p][i].Value].referenceName})");
  218. appendAnd = true;
  219. break;
  220. }
  221. case KeywordType.Boolean:
  222. {
  223. // HLSL does not support a !value predicate
  224. if (permutations[p][i].Value != 0)
  225. {
  226. continue;
  227. }
  228. sb.Append($"{and}defined({permutations[p][i].Key.referenceName})");
  229. appendAnd = true;
  230. break;
  231. }
  232. default:
  233. throw new ArgumentOutOfRangeException();
  234. }
  235. }
  236. }
  237. sb.AppendNewLine();
  238. // Define the matching permutation keyword
  239. sb.IncreaseIndent();
  240. sb.AppendLine($"#define KEYWORD_PERMUTATION_{p}");
  241. sb.DecreaseIndent();
  242. }
  243. // End statement
  244. sb.AppendLine("#endif");
  245. }
  246. }
  247. }