mathe/Library/PackageCache/com.unity.shadergraph@14.0.8/Editor/Data/Util/KeywordUtil.cs
2024-09-20 20:30:10 +02:00

275 lines
10 KiB
C#

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");
}
}
}