123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using UnityEditor.ShaderGraph.Drawing;
- using UnityEngine;
- using UnityEditor.ShaderGraph.Internal;
-
- namespace UnityEditor.ShaderGraph
- {
- static class BuiltinKeyword
- {
- [BuiltinKeyword]
- public static KeywordDescriptor QualityKeyword()
- {
- return new KeywordDescriptor()
- {
- displayName = "Material Quality",
- referenceName = "MATERIAL_QUALITY",
- type = KeywordType.Enum,
- definition = KeywordDefinition.MultiCompile,
- scope = KeywordScope.Global,
- value = 0,
- entries = new KeywordEntry[]
- {
- new KeywordEntry("High", "HIGH"),
- new KeywordEntry("Medium", "MEDIUM"),
- new KeywordEntry("Low", "LOW"),
- },
- stages = KeywordShaderStage.All,
- };
- }
- }
-
- static class KeywordUtil
- {
- public static IEnumerable<KeywordDescriptor> GetBuiltinKeywordDescriptors() =>
- TypeCache.GetMethodsWithAttribute<BuiltinKeywordAttribute>()
- .Where(method => method.IsStatic && method.ReturnType == typeof(KeywordDescriptor))
- .Select(method =>
- (KeywordDescriptor)method.Invoke(null, new object[0] { }));
-
- public static ConcreteSlotValueType ToConcreteSlotValueType(this KeywordType keywordType)
- {
- switch (keywordType)
- {
- case KeywordType.Boolean:
- return ConcreteSlotValueType.Boolean;
- case KeywordType.Enum:
- return ConcreteSlotValueType.Vector1;
- default:
- throw new ArgumentOutOfRangeException();
- }
- }
-
- public static string ToDeclarationSuffix(this KeywordScope scope)
- {
- switch (scope)
- {
- case KeywordScope.Local:
- return "_local";
- default:
- return string.Empty;
- }
- }
-
- public static string ToDeclarationString(this KeywordDefinition keywordDefinition)
- {
- switch (keywordDefinition)
- {
- case KeywordDefinition.MultiCompile:
- return "multi_compile";
- case KeywordDefinition.ShaderFeature:
- return "shader_feature";
- default:
- return string.Empty;
- }
- }
-
- static void GenerateKeywordPragmaStrings(
- string keywordReferenceName,
- KeywordDefinition keywordDefinition,
- KeywordScope keywordScope,
- KeywordShaderStage keywordStages,
- string keywordVariantsString,
- Action<string> PragmaStringAction)
- {
- string definitionString = keywordDefinition.ToDeclarationString();
- string scopeString = keywordScope.ToDeclarationSuffix();
-
- // check the active shader stages
- if ((keywordStages == KeywordShaderStage.All) || (keywordStages == 0)) // 0 is a default, so assume that means ALL
- {
- PragmaStringAction($"#pragma {definitionString}{scopeString} {keywordVariantsString}");
- }
- else
- {
- // have to process each stage separately
- for (int shaderStage = (int)KeywordShaderStage.Vertex; shaderStage <= (int)keywordStages; shaderStage = shaderStage * 2)
- {
- if (((int)keywordStages & shaderStage) != 0)
- {
- var keywordStage = (KeywordShaderStage)shaderStage;
- var stageString = keywordStage.ToKeywordStagesString();
- PragmaStringAction($"#pragma {definitionString}{scopeString}{stageString} {keywordVariantsString}");
- }
- }
- }
- }
-
- public static void GenerateEnumKeywordPragmaStrings(
- string keywordReferenceName,
- KeywordDefinition keywordDefinition,
- KeywordScope keywordScope,
- KeywordShaderStage keywordStages,
- IEnumerable<KeywordEntry> keywordEntries,
- Action<string> pragmaStringAction)
- {
- if (keywordDefinition != KeywordDefinition.Predefined)
- {
- var entryStrings = keywordEntries.Select(x => string.IsNullOrEmpty(x.referenceName) ? "_" : $"{keywordReferenceName}_{x.referenceName}");
- string variantsString = string.Join(" ", entryStrings);
- GenerateKeywordPragmaStrings(keywordReferenceName, keywordDefinition, keywordScope, keywordStages, variantsString, pragmaStringAction);
- }
- }
-
- public static void GenerateBooleanKeywordPragmaStrings(
- string keywordReferenceName,
- KeywordDefinition keywordDefinition,
- KeywordScope keywordScope,
- KeywordShaderStage keywordStages,
- Action<string> pragmaStringAction)
- {
- if (keywordDefinition != KeywordDefinition.Predefined)
- {
- string variantsString = $"_ {keywordReferenceName}";
- GenerateKeywordPragmaStrings(keywordReferenceName, keywordDefinition, keywordScope, keywordStages, variantsString, pragmaStringAction);
- }
- }
-
- public static string ToKeywordStagesString(this KeywordShaderStage stages)
- {
- string outString = "";
-
- if (stages == KeywordShaderStage.All)
- return outString;
- if (stages == KeywordShaderStage.Vertex)
- outString += "_vertex";
- if (stages == KeywordShaderStage.Fragment)
- outString += "_fragment";
- if (stages == KeywordShaderStage.Geometry)
- outString += "_geometry";
- if (stages == KeywordShaderStage.Hull)
- outString += "_hull";
- if (stages == KeywordShaderStage.Domain)
- outString += "_domain";
- if (stages == KeywordShaderStage.RayTracing)
- outString += "_raytracing";
-
- return outString;
- }
-
- public static string ToDefineString(this KeywordDescriptor keyword, int value)
- {
- switch (keyword.type)
- {
- case KeywordType.Boolean:
- return value == 1 ? $"#define {keyword.referenceName} 1" : string.Empty;
- case KeywordType.Enum:
- return $"#define {keyword.referenceName}_{keyword.entries[value].referenceName}";
- default:
- throw new ArgumentOutOfRangeException();
- }
- }
-
- public static string GetKeywordPermutationSetConditional(List<int> permutationSet)
- {
- StringBuilder sb = new StringBuilder();
- sb.Append("#if ");
-
- for (int i = 0; i < permutationSet.Count; i++)
- {
- // Subsequent permutation predicates require ||
- if (i != 0)
- sb.Append(" || ");
-
- // Append permutation
- sb.Append($"defined(KEYWORD_PERMUTATION_{permutationSet[i]})");
- }
-
- return sb.ToString();
- }
-
- public static string GetKeywordPermutationConditional(int permutation)
- {
- return $"#if defined(KEYWORD_PERMUTATION_{permutation})";
- }
-
- public static void GetKeywordPermutationDeclarations(ShaderStringBuilder sb, List<List<KeyValuePair<ShaderKeyword, int>>> permutations)
- {
- if (permutations.Count == 0)
- return;
-
- for (int p = 0; p < permutations.Count; p++)
- {
- // ShaderStringBuilder.Append doesnt apply indentation
- sb.TryAppendIndentation();
-
- // Append correct if
- bool isLast = false;
- if (p == 0)
- {
- sb.Append("#if ");
- }
- else if (p == permutations.Count - 1)
- {
- sb.Append("#else");
- isLast = true;
- }
- else
- {
- sb.Append("#elif ");
- }
-
- // Last permutation is always #else
- if (!isLast)
- {
- // Track whether && is required
- bool appendAnd = false;
-
- // Iterate all keywords that are part of the permutation
- for (int i = 0; i < permutations[p].Count; i++)
- {
- // When previous keyword was inserted subsequent requires &&
- string and = appendAnd ? " && " : string.Empty;
-
- switch (permutations[p][i].Key.keywordType)
- {
- case KeywordType.Enum:
- {
- sb.Append($"{and}defined({permutations[p][i].Key.referenceName}_{permutations[p][i].Key.entries[permutations[p][i].Value].referenceName})");
- appendAnd = true;
- break;
- }
- case KeywordType.Boolean:
- {
- // HLSL does not support a !value predicate
- if (permutations[p][i].Value != 0)
- {
- continue;
- }
-
- sb.Append($"{and}defined({permutations[p][i].Key.referenceName})");
- appendAnd = true;
- break;
- }
- default:
- throw new ArgumentOutOfRangeException();
- }
- }
- }
- sb.AppendNewLine();
-
- // Define the matching permutation keyword
- sb.IncreaseIndent();
- sb.AppendLine($"#define KEYWORD_PERMUTATION_{p}");
- sb.DecreaseIndent();
- }
-
- // End statement
- sb.AppendLine("#endif");
- }
- }
- }
|