浏览代码

hlsl generator: tabs->spaces

/main
vlad-andreev 8 年前
当前提交
55ec4129
共有 3 个文件被更改,包括 748 次插入748 次删除
  1. 522
      Assets/ShaderGenerator/CSharpToHLSL.cs
  2. 16
      Assets/ShaderGenerator/ShaderGeneratorMenu.cs
  3. 958
      Assets/ShaderGenerator/ShaderTypeGeneration.cs

522
Assets/ShaderGenerator/CSharpToHLSL.cs


namespace UnityEngine.ScriptableRenderLoop
{
public class CSharpToHLSL
{
public static bool GenerateHLSL(System.Type type, GenerateHLSL attribute, out string shaderSource)
{
List<string> errors;
return GenerateHLSL(type, attribute, out shaderSource, out errors);
}
public class CSharpToHLSL
{
public static bool GenerateHLSL(System.Type type, GenerateHLSL attribute, out string shaderSource)
{
List<string> errors;
return GenerateHLSL(type, attribute, out shaderSource, out errors);
}
public static bool GenerateHLSL(System.Type type, GenerateHLSL attribute, out string shaderSource, out List<string> errors)
{
ShaderTypeGenerator gen = new ShaderTypeGenerator(type, attribute);
bool success = gen.Generate();
public static bool GenerateHLSL(System.Type type, GenerateHLSL attribute, out string shaderSource, out List<string> errors)
{
ShaderTypeGenerator gen = new ShaderTypeGenerator(type, attribute);
bool success = gen.Generate();
if (success)
{
shaderSource = gen.Emit();
}
else
{
shaderSource = null;
}
if (success)
{
shaderSource = gen.Emit();
}
else
{
shaderSource = null;
}
errors = gen.errors;
return success;
}
errors = gen.errors;
return success;
}
public static void GenerateAll()
{
m_typeName = new Dictionary<string, ShaderTypeGenerator>();
public static void GenerateAll()
{
m_typeName = new Dictionary<string, ShaderTypeGenerator>();
// Iterate over assemblyList, discover all applicable types with fully qualified names
var assemblyList = AssemblyEnumerator.EnumerateReferencedAssemblies(Assembly.GetCallingAssembly());
// Iterate over assemblyList, discover all applicable types with fully qualified names
var assemblyList = AssemblyEnumerator.EnumerateReferencedAssemblies(Assembly.GetCallingAssembly());
foreach (var assembly in assemblyList)
{
Type[] types = assembly.GetExportedTypes();
foreach (var assembly in assemblyList)
{
Type[] types = assembly.GetExportedTypes();
foreach (var type in types)
{
object[] attributes = type.GetCustomAttributes(true);
foreach (var type in types)
{
object[] attributes = type.GetCustomAttributes(true);
foreach (var attr in attributes)
{
if (attr is GenerateHLSL)
{
Type parent = type.DeclaringType;
if (parent != null)
{
Debug.LogError("The GenerateHLSL attribute not supported on nested classes (" + type.FullName + "), skipping.");
}
else
{
ShaderTypeGenerator gen;
if (m_typeName.TryGetValue(type.FullName, out gen))
{
Debug.LogError("Duplicate typename with the GenerateHLSL attribute detected: " + type.FullName +
" declared in both " + gen.type.Assembly.FullName + " and " + type.Assembly.FullName + ". Skipping the second instance.");
}
m_typeName[type.FullName] = new ShaderTypeGenerator(type, attr as GenerateHLSL);
}
}
}
}
}
foreach (var attr in attributes)
{
if (attr is GenerateHLSL)
{
Type parent = type.DeclaringType;
if (parent != null)
{
Debug.LogError("The GenerateHLSL attribute not supported on nested classes (" + type.FullName + "), skipping.");
}
else
{
ShaderTypeGenerator gen;
if (m_typeName.TryGetValue(type.FullName, out gen))
{
Debug.LogError("Duplicate typename with the GenerateHLSL attribute detected: " + type.FullName +
" declared in both " + gen.type.Assembly.FullName + " and " + type.Assembly.FullName + ". Skipping the second instance.");
}
m_typeName[type.FullName] = new ShaderTypeGenerator(type, attr as GenerateHLSL);
}
}
}
}
}
// Now that we have extracted all the typenames that we care about, parse all .cs files in all asset
// paths and figure out in which files those types are actually declared.
m_sourceGenerators = new Dictionary<string, List<ShaderTypeGenerator>>();
// Now that we have extracted all the typenames that we care about, parse all .cs files in all asset
// paths and figure out in which files those types are actually declared.
m_sourceGenerators = new Dictionary<string, List<ShaderTypeGenerator>>();
var assetPaths = AssetDatabase.GetAllAssetPaths().Where(s => s.EndsWith(".cs")).ToList();
foreach (var assetPath in assetPaths)
{
LoadTypes(assetPath);
}
var assetPaths = AssetDatabase.GetAllAssetPaths().Where(s => s.EndsWith(".cs")).ToList();
foreach (var assetPath in assetPaths)
{
LoadTypes(assetPath);
}
// Finally, write out the generated code
foreach (var it in m_sourceGenerators)
{
string fileName = it.Key + ".hlsl";
bool skipFile = false;
foreach (var gen in it.Value)
{
if (!gen.Generate())
{
// Error reporting will be done by the generator. Skip this file.
gen.PrintErrors();
skipFile = true;
break; ;
}
}
// Finally, write out the generated code
foreach (var it in m_sourceGenerators)
{
string fileName = it.Key + ".hlsl";
bool skipFile = false;
foreach (var gen in it.Value)
{
if (!gen.Generate())
{
// Error reporting will be done by the generator. Skip this file.
gen.PrintErrors();
skipFile = true;
break; ;
}
}
if (!skipFile)
{
using (System.IO.StreamWriter writer = File.CreateText(fileName))
{
writer.Write("//\n");
writer.Write("// This file was automatically generated from " + it.Key + ". Please don't edit by hand.\n");
writer.Write("//\n\n");
if (!skipFile)
{
using (System.IO.StreamWriter writer = File.CreateText(fileName))
{
writer.Write("//\n");
writer.Write("// This file was automatically generated from " + it.Key + ". Please don't edit by hand.\n");
writer.Write("//\n\n");
foreach (var gen in it.Value)
{
if (gen.hasStatics)
{
writer.Write(gen.EmitDefines() + "\n");
}
}
foreach (var gen in it.Value)
{
if (gen.hasStatics)
{
writer.Write(gen.EmitDefines() + "\n");
}
}
foreach (var gen in it.Value)
{
if (gen.hasFields)
{
writer.Write(gen.EmitTypeDecl() + "\n");
}
}
foreach (var gen in it.Value)
{
if (gen.hasFields)
{
writer.Write(gen.EmitTypeDecl() + "\n");
}
}
foreach (var gen in it.Value)
{
if (gen.hasFields && !gen.IsSimple())
{
writer.Write(gen.EmitAccessors() + "\n");
}
}
foreach (var gen in it.Value)
{
if (gen.hasFields && !gen.IsSimple())
{
writer.Write(gen.EmitAccessors() + "\n");
}
}
writer.Write("\n");
}
}
}
}
writer.Write("\n");
}
}
}
}
static Dictionary<string, ShaderTypeGenerator> m_typeName;
static Dictionary<string, ShaderTypeGenerator> m_typeName;
static void LoadTypes(string fileName)
{
using (var parser = ParserFactory.CreateParser(fileName))
{
// @TODO any standard preprocessor symbols we need?
static void LoadTypes(string fileName)
{
using (var parser = ParserFactory.CreateParser(fileName))
{
// @TODO any standard preprocessor symbols we need?
/*var uniqueSymbols = new HashSet<string>(definedSymbols.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries));
/*var uniqueSymbols = new HashSet<string>(definedSymbols.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries));
parser.Lexer.EvaluateConditionalCompilation = true;
parser.Lexer.EvaluateConditionalCompilation = true;
parser.Parse();
try
{
var visitor = new NamespaceVisitor();
VisitorData data = new VisitorData();
data.m_typeName = m_typeName;
parser.CompilationUnit.AcceptVisitor(visitor, data);
parser.Parse();
try
{
var visitor = new NamespaceVisitor();
VisitorData data = new VisitorData();
data.m_typeName = m_typeName;
parser.CompilationUnit.AcceptVisitor(visitor, data);
if (data.generators.Count > 0)
m_sourceGenerators[fileName] = data.generators;
if (data.generators.Count > 0)
m_sourceGenerators[fileName] = data.generators;
}
catch
{
// does NRefactory throw anything we can handle here?
throw;
}
}
}
}
catch
{
// does NRefactory throw anything we can handle here?
throw;
}
}
}
static Dictionary<string, List<ShaderTypeGenerator>> m_sourceGenerators;
static Dictionary<string, List<ShaderTypeGenerator>> m_sourceGenerators;
class VisitorData
{
public VisitorData()
{
currentNamespaces = new Stack<string>();
currentClasses = new Stack<string>();
generators = new List<ShaderTypeGenerator>();
}
class VisitorData
{
public VisitorData()
{
currentNamespaces = new Stack<string>();
currentClasses = new Stack<string>();
generators = new List<ShaderTypeGenerator>();
}
public string GetTypePrefix()
{
string fullNamespace = string.Empty;
public string GetTypePrefix()
{
string fullNamespace = string.Empty;
string separator = "";
foreach (string ns in currentClasses)
{
fullNamespace = ns + "+" + fullNamespace;
}
string separator = "";
foreach (string ns in currentClasses)
{
fullNamespace = ns + "+" + fullNamespace;
}
foreach (string ns in currentNamespaces)
{
if (fullNamespace == string.Empty)
{
separator = ".";
fullNamespace = ns;
}
else
fullNamespace = ns + "." + fullNamespace;
}
foreach (string ns in currentNamespaces)
{
if (fullNamespace == string.Empty)
{
separator = ".";
fullNamespace = ns;
}
else
fullNamespace = ns + "." + fullNamespace;
}
string name = "";
if (fullNamespace != string.Empty)
{
name = fullNamespace + separator + name;
}
return name;
}
string name = "";
if (fullNamespace != string.Empty)
{
name = fullNamespace + separator + name;
}
return name;
}
public Stack<string> currentNamespaces;
public Stack<string> currentClasses;
public List<ShaderTypeGenerator> generators;
public Dictionary<string, ShaderTypeGenerator> m_typeName;
}
public Stack<string> currentNamespaces;
public Stack<string> currentClasses;
public List<ShaderTypeGenerator> generators;
public Dictionary<string, ShaderTypeGenerator> m_typeName;
}
class NamespaceVisitor : AbstractAstVisitor
{
public override object VisitNamespaceDeclaration(ICSharpCode.NRefactory.Ast.NamespaceDeclaration namespaceDeclaration, object data)
{
VisitorData visitorData = (VisitorData)data;
visitorData.currentNamespaces.Push(namespaceDeclaration.Name);
namespaceDeclaration.AcceptChildren(this, visitorData);
visitorData.currentNamespaces.Pop();
class NamespaceVisitor : AbstractAstVisitor
{
public override object VisitNamespaceDeclaration(ICSharpCode.NRefactory.Ast.NamespaceDeclaration namespaceDeclaration, object data)
{
VisitorData visitorData = (VisitorData)data;
visitorData.currentNamespaces.Push(namespaceDeclaration.Name);
namespaceDeclaration.AcceptChildren(this, visitorData);
visitorData.currentNamespaces.Pop();
return null;
}
return null;
}
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
{
// Structured types only
if (typeDeclaration.Type == ClassType.Class || typeDeclaration.Type == ClassType.Struct || typeDeclaration.Type == ClassType.Enum)
{
VisitorData visitorData = (VisitorData)data;
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
{
// Structured types only
if (typeDeclaration.Type == ClassType.Class || typeDeclaration.Type == ClassType.Struct || typeDeclaration.Type == ClassType.Enum)
{
VisitorData visitorData = (VisitorData)data;
string name = visitorData.GetTypePrefix() + typeDeclaration.Name;
string name = visitorData.GetTypePrefix() + typeDeclaration.Name;
ShaderTypeGenerator gen;
if (visitorData.m_typeName.TryGetValue(name, out gen))
{
visitorData.generators.Add(gen);
}
ShaderTypeGenerator gen;
if (visitorData.m_typeName.TryGetValue(name, out gen))
{
visitorData.generators.Add(gen);
}
visitorData.currentClasses.Push(typeDeclaration.Name);
typeDeclaration.AcceptChildren(this, visitorData);
visitorData.currentClasses.Pop();
}
visitorData.currentClasses.Push(typeDeclaration.Name);
typeDeclaration.AcceptChildren(this, visitorData);
visitorData.currentClasses.Pop();
}
return null;
}
}
}
return null;
}
}
}
// Helper class to recursively enumerate assemblies referenced by the calling assembly, including unloaded ones
static class AssemblyEnumerator
{
public static List<Assembly> EnumerateReferencedAssemblies(Assembly assembly)
{
Dictionary<string, Assembly> assemblies = assembly.GetReferencedAssembliesRecursive();
assemblies[GetName(assembly.FullName)] = assembly;
return assemblies.Values.ToList();
}
// Helper class to recursively enumerate assemblies referenced by the calling assembly, including unloaded ones
static class AssemblyEnumerator
{
public static List<Assembly> EnumerateReferencedAssemblies(Assembly assembly)
{
Dictionary<string, Assembly> assemblies = assembly.GetReferencedAssembliesRecursive();
assemblies[GetName(assembly.FullName)] = assembly;
return assemblies.Values.ToList();
}
public static Dictionary<string, Assembly> GetReferencedAssembliesRecursive(this Assembly assembly)
{
assemblies = new Dictionary<string, Assembly>();
InternalGetDependentAssembliesRecursive(assembly);
public static Dictionary<string, Assembly> GetReferencedAssembliesRecursive(this Assembly assembly)
{
assemblies = new Dictionary<string, Assembly>();
InternalGetDependentAssembliesRecursive(assembly);
// Skip assemblies from GAC (@TODO: any reason we'd want to include them?)
var keysToRemove = assemblies.Values.Where(
o => o.GlobalAssemblyCache == true).ToList();
// Skip assemblies from GAC (@TODO: any reason we'd want to include them?)
var keysToRemove = assemblies.Values.Where(
o => o.GlobalAssemblyCache == true).ToList();
foreach (var k in keysToRemove)
{
assemblies.Remove(GetName(k.FullName));
}
foreach (var k in keysToRemove)
{
assemblies.Remove(GetName(k.FullName));
}
return assemblies;
}
return assemblies;
}
private static void InternalGetDependentAssembliesRecursive(Assembly assembly)
{
// Load assemblies with newest versions first.
var referencedAssemblies = assembly.GetReferencedAssemblies()
.OrderByDescending(o => o.Version);
private static void InternalGetDependentAssembliesRecursive(Assembly assembly)
{
// Load assemblies with newest versions first.
var referencedAssemblies = assembly.GetReferencedAssemblies()
.OrderByDescending(o => o.Version);
foreach (var r in referencedAssemblies)
{
if (String.IsNullOrEmpty(assembly.FullName))
{
continue;
}
foreach (var r in referencedAssemblies)
{
if (String.IsNullOrEmpty(assembly.FullName))
{
continue;
}
if (assemblies.ContainsKey(GetName(r.FullName)) == false)
{
try
{
// Ensure that the assembly is loaded
var a = Assembly.Load(r.FullName);
assemblies[GetName(a.FullName)] = a;
InternalGetDependentAssembliesRecursive(a);
}
catch
{
// Missing dll, ignore.
}
}
}
}
if (assemblies.ContainsKey(GetName(r.FullName)) == false)
{
try
{
// Ensure that the assembly is loaded
var a = Assembly.Load(r.FullName);
assemblies[GetName(a.FullName)] = a;
InternalGetDependentAssembliesRecursive(a);
}
catch
{
// Missing dll, ignore.
}
}
}
}
static string GetName(string name)
{
return name.Split(',')[0];
}
static string GetName(string name)
{
return name.Split(',')[0];
}
static Dictionary<string, Assembly> assemblies;
}
static Dictionary<string, Assembly> assemblies;
}
};

16
Assets/ShaderGenerator/ShaderGeneratorMenu.cs


namespace UnityEngine.ScriptableRenderLoop
{
public class ShaderGeneratorMenu
{
[UnityEditor.MenuItem("Renderloop/Generate Shader Includes")]
static void GenerateShaderIncludes()
{
CSharpToHLSL.GenerateAll();
}
}
public class ShaderGeneratorMenu
{
[UnityEditor.MenuItem("Renderloop/Generate Shader Includes")]
static void GenerateShaderIncludes()
{
CSharpToHLSL.GenerateAll();
}
}
}

958
Assets/ShaderGenerator/ShaderTypeGeneration.cs


namespace UnityEngine.ScriptableRenderLoop
{
public enum PackingRules
{
Exact,
Aggressive
};
public enum PackingRules
{
Exact,
Aggressive
};
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class | AttributeTargets.Enum)]
public class GenerateHLSL : System.Attribute
{
public PackingRules packingRules;
public bool simple;
public int debugCounterStart;
public GenerateHLSL(PackingRules rules = PackingRules.Exact, bool simple = false, int debugCounterStart = 1)
{
packingRules = rules;
this.simple = simple;
this.debugCounterStart = debugCounterStart;
}
}
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class | AttributeTargets.Enum)]
public class GenerateHLSL : System.Attribute
{
public PackingRules packingRules;
public bool simple;
public int debugCounterStart;
public GenerateHLSL(PackingRules rules = PackingRules.Exact, bool simple = false, int debugCounterStart = 1)
{
packingRules = rules;
this.simple = simple;
this.debugCounterStart = debugCounterStart;
}
}
[AttributeUsage(AttributeTargets.Field)]
public class SurfaceDataAttributes : System.Attribute
{
public string displayName;
public SurfaceDataAttributes(string displayName = "")
{
this.displayName = displayName;
}
}
[AttributeUsage(AttributeTargets.Field)]
public class SurfaceDataAttributes : System.Attribute
{
public string displayName;
public SurfaceDataAttributes(string displayName = "")
{
this.displayName = displayName;
}
}
internal class ShaderTypeGenerator
{
public ShaderTypeGenerator(Type type, GenerateHLSL attr)
{
this.type = type;
this.attr = attr;
debugCounter = 0;
}
internal class ShaderTypeGenerator
{
public ShaderTypeGenerator(Type type, GenerateHLSL attr)
{
this.type = type;
this.attr = attr;
debugCounter = 0;
}
enum PrimitiveType
{
Float, Int, UInt
};
enum PrimitiveType
{
Float, Int, UInt
};
static string PrimitiveToString(PrimitiveType type, int rows, int cols)
{
string text = "";
switch (type)
{
case PrimitiveType.Float:
text = "float";
break;
case PrimitiveType.Int:
text = "int";
break;
case PrimitiveType.UInt:
text = "uint";
break;
}
static string PrimitiveToString(PrimitiveType type, int rows, int cols)
{
string text = "";
switch (type)
{
case PrimitiveType.Float:
text = "float";
break;
case PrimitiveType.Int:
text = "int";
break;
case PrimitiveType.UInt:
text = "uint";
break;
}
if (rows > 1)
{
text += rows.ToString();
if (cols > 1)
{
text += "x" + cols.ToString();
}
}
if (rows > 1)
{
text += rows.ToString();
if (cols > 1)
{
text += "x" + cols.ToString();
}
}
return text;
}
return text;
}
class Accessor
{
public Accessor(PrimitiveType type, string name, int rows, int cols)
{
this.name = name;
this.fullType = PrimitiveToString(type, rows, cols);
field = name;
}
class Accessor
{
public Accessor(PrimitiveType type, string name, int rows, int cols)
{
this.name = name;
this.fullType = PrimitiveToString(type, rows, cols);
field = name;
}
Accessor(string name, string swizzle, string field, string fullType)
{
this.name = name;
this.field = field;
this.fullType = fullType;
}
Accessor(string name, string swizzle, string field, string fullType)
{
this.name = name;
this.field = field;
this.fullType = fullType;
}
public string name;
public string field;
public string fullType;
};
public string name;
public string field;
public string fullType;
};
class ShaderFieldInfo : ICloneable
{
public ShaderFieldInfo(PrimitiveType type, string name, int rows, int cols)
{
this.type = type;
this.name = originalName = name;
this.rows = rows;
this.cols = cols;
this.comment = "";
swizzleOffset = 0;
packed = false;
accessor = new Accessor(type, name, rows, cols);
}
public ShaderFieldInfo(PrimitiveType type, string name, int rows, int cols, string comment)
{
this.type = type;
this.name = originalName = name;
this.rows = rows;
this.cols = cols;
this.comment = comment;
swizzleOffset = 0;
packed = false;
accessor = new Accessor(type, name, rows, cols);
}
class ShaderFieldInfo : ICloneable
{
public ShaderFieldInfo(PrimitiveType type, string name, int rows, int cols)
{
this.type = type;
this.name = originalName = name;
this.rows = rows;
this.cols = cols;
this.comment = "";
swizzleOffset = 0;
packed = false;
accessor = new Accessor(type, name, rows, cols);
}
public ShaderFieldInfo(PrimitiveType type, string name, int rows, int cols, string comment)
{
this.type = type;
this.name = originalName = name;
this.rows = rows;
this.cols = cols;
this.comment = comment;
swizzleOffset = 0;
packed = false;
accessor = new Accessor(type, name, rows, cols);
}
public string typeString
{
get { return PrimitiveToString(type, rows, cols); }
}
public string typeString
{
get { return PrimitiveToString(type, rows, cols); }
}
public string DeclString()
{
return PrimitiveToString(type, rows, cols) + " " + name;
}
public string DeclString()
{
return PrimitiveToString(type, rows, cols) + " " + name;
}
public override string ToString()
{
string text = DeclString() + ";";
if (comment.Length > 0)
{
text += " // " + comment;
}
return text;
}
public override string ToString()
{
string text = DeclString() + ";";
if (comment.Length > 0)
{
text += " // " + comment;
}
return text;
}
public int elementCount
{
get { return rows * cols; }
}
public int elementCount
{
get { return rows * cols; }
}
public object Clone()
{
ShaderFieldInfo info = new ShaderFieldInfo(type, name, rows, cols, comment);
info.swizzleOffset = swizzleOffset;
info.packed = packed;
info.accessor = accessor;
return info;
}
public object Clone()
{
ShaderFieldInfo info = new ShaderFieldInfo(type, name, rows, cols, comment);
info.swizzleOffset = swizzleOffset;
info.packed = packed;
info.accessor = accessor;
return info;
}
public PrimitiveType type;
public string name;
public string originalName;
public string comment;
public int rows;
public int cols;
public int swizzleOffset;
public bool packed;
public Accessor accessor;
};
public PrimitiveType type;
public string name;
public string originalName;
public string comment;
public int rows;
public int cols;
public int swizzleOffset;
public bool packed;
public Accessor accessor;
};
void Error(string error)
{
if (errors == null)
{
errors = new List<string>();
}
errors.Add("Failed to generate shader type for " + type.ToString() + ": " + error);
}
void Error(string error)
{
if (errors == null)
{
errors = new List<string>();
}
errors.Add("Failed to generate shader type for " + type.ToString() + ": " + error);
}
public void PrintErrors()
{
if (errors != null)
{
foreach (var e in errors)
{
Debug.LogError(e);
}
}
}
public void PrintErrors()
{
if (errors != null)
{
foreach (var e in errors)
{
Debug.LogError(e);
}
}
}
void EmitPrimitiveType(PrimitiveType type, int elements, string name, string comment, List<ShaderFieldInfo> fields)
{
fields.Add(new ShaderFieldInfo(type, name, elements, 1, comment));
}
void EmitPrimitiveType(PrimitiveType type, int elements, string name, string comment, List<ShaderFieldInfo> fields)
{
fields.Add(new ShaderFieldInfo(type, name, elements, 1, comment));
}
void EmitMatrixType(PrimitiveType type, int rows, int cols, string name, string comment, List<ShaderFieldInfo> fields)
{
fields.Add(new ShaderFieldInfo(type, name, rows, cols, comment));
}
void EmitMatrixType(PrimitiveType type, int rows, int cols, string name, string comment, List<ShaderFieldInfo> fields)
{
fields.Add(new ShaderFieldInfo(type, name, rows, cols, comment));
}
bool ExtractComplex(FieldInfo field, List<ShaderFieldInfo> shaderFields)
{
List<FieldInfo> floatFields = new List<FieldInfo>();
List<FieldInfo> intFields = new List<FieldInfo>();
List<FieldInfo> uintFields = new List<FieldInfo>();
string[] descs = new string[4] { "x: ", "y: ", "z: ", "w: " };
int numFields = 0;
bool ExtractComplex(FieldInfo field, List<ShaderFieldInfo> shaderFields)
{
List<FieldInfo> floatFields = new List<FieldInfo>();
List<FieldInfo> intFields = new List<FieldInfo>();
List<FieldInfo> uintFields = new List<FieldInfo>();
string[] descs = new string[4] { "x: ", "y: ", "z: ", "w: " };
int numFields = 0;
string fieldName = "'" + field.FieldType.Name + " " + field.Name + "'";
string fieldName = "'" + field.FieldType.Name + " " + field.Name + "'";
foreach (FieldInfo subField in field.FieldType.GetFields())
{
if (subField.IsStatic)
continue;
foreach (FieldInfo subField in field.FieldType.GetFields())
{
if (subField.IsStatic)
continue;
if (!subField.FieldType.IsPrimitive)
{
Error("'" + fieldName + "' can not be packed into a register, since it contains a non-primitive field type '" + subField.FieldType + "'");
return false;
}
if (subField.FieldType == typeof(float))
floatFields.Add(subField);
else if (subField.FieldType == typeof(int))
intFields.Add(subField);
else if (subField.FieldType == typeof(uint))
uintFields.Add(subField);
else
{
Error("'" + fieldName + "' can not be packed into a register, since it contains an unsupported field type '" + subField.FieldType + "'");
return false;
}
if (!subField.FieldType.IsPrimitive)
{
Error("'" + fieldName + "' can not be packed into a register, since it contains a non-primitive field type '" + subField.FieldType + "'");
return false;
}
if (subField.FieldType == typeof(float))
floatFields.Add(subField);
else if (subField.FieldType == typeof(int))
intFields.Add(subField);
else if (subField.FieldType == typeof(uint))
uintFields.Add(subField);
else
{
Error("'" + fieldName + "' can not be packed into a register, since it contains an unsupported field type '" + subField.FieldType + "'");
return false;
}
if (numFields == 4)
{
Error("'" + fieldName + "' can not be packed into a register because it contains more than 4 fields.");
return false;
}
if (numFields == 4)
{
Error("'" + fieldName + "' can not be packed into a register because it contains more than 4 fields.");
return false;
}
descs[numFields] += subField.Name + " ";
numFields++;
}
Array.Resize(ref descs, numFields);
descs[numFields] += subField.Name + " ";
numFields++;
}
Array.Resize(ref descs, numFields);
string comment = string.Concat(descs);
string mismatchErrorMsg = "'" + fieldName + "' can not be packed into a single register because it contains mixed basic types.";
string comment = string.Concat(descs);
string mismatchErrorMsg = "'" + fieldName + "' can not be packed into a single register because it contains mixed basic types.";
if (floatFields.Count > 0)
{
if (intFields.Count + uintFields.Count > 0)
{
Error(mismatchErrorMsg);
return false;
}
EmitPrimitiveType(PrimitiveType.Float, floatFields.Count, field.Name, comment, shaderFields);
}
else if (intFields.Count > 0)
{
if (floatFields.Count + uintFields.Count > 0)
{
Error(mismatchErrorMsg);
return false;
}
EmitPrimitiveType(PrimitiveType.Int, intFields.Count, field.Name, "", shaderFields);
}
else if (uintFields.Count > 0)
{
if (floatFields.Count + intFields.Count > 0)
{
Error(mismatchErrorMsg);
return false;
}
EmitPrimitiveType(PrimitiveType.UInt, uintFields.Count, field.Name, "", shaderFields);
}
else
{
// Empty struct.
}
if (floatFields.Count > 0)
{
if (intFields.Count + uintFields.Count > 0)
{
Error(mismatchErrorMsg);
return false;
}
EmitPrimitiveType(PrimitiveType.Float, floatFields.Count, field.Name, comment, shaderFields);
}
else if (intFields.Count > 0)
{
if (floatFields.Count + uintFields.Count > 0)
{
Error(mismatchErrorMsg);
return false;
}
EmitPrimitiveType(PrimitiveType.Int, intFields.Count, field.Name, "", shaderFields);
}
else if (uintFields.Count > 0)
{
if (floatFields.Count + intFields.Count > 0)
{
Error(mismatchErrorMsg);
return false;
}
EmitPrimitiveType(PrimitiveType.UInt, uintFields.Count, field.Name, "", shaderFields);
}
else
{
// Empty struct.
}
return true;
}
return true;
}
enum MergeResult
{
Merged,
Full,
Failed
};
enum MergeResult
{
Merged,
Full,
Failed
};
MergeResult PackFields(ShaderFieldInfo info, ref ShaderFieldInfo merged)
{
if (merged.elementCount % 4 == 0)
{
return MergeResult.Full;
}
MergeResult PackFields(ShaderFieldInfo info, ref ShaderFieldInfo merged)
{
if (merged.elementCount % 4 == 0)
{
return MergeResult.Full;
}
if (info.type != merged.type)
{
Error("can't merge '" + merged.DeclString() + "' and '" + info.DeclString() + "' into the same register because they have incompatible types. Consider reordering the fields so that adjacent fields have the same primitive type.");
return MergeResult.Failed; // incompatible types
}
if (info.type != merged.type)
{
Error("can't merge '" + merged.DeclString() + "' and '" + info.DeclString() + "' into the same register because they have incompatible types. Consider reordering the fields so that adjacent fields have the same primitive type.");
return MergeResult.Failed; // incompatible types
}
if (info.cols > 1 || merged.cols > 1)
{
Error("merging matrix types not yet supported ('" + merged.DeclString() + "' and '" + info.DeclString() + "'). Consider reordering the fields to place matrix-typed variables on four-component vector boundaries.");
return MergeResult.Failed; // don't merge matrix types
}
if (info.cols > 1 || merged.cols > 1)
{
Error("merging matrix types not yet supported ('" + merged.DeclString() + "' and '" + info.DeclString() + "'). Consider reordering the fields to place matrix-typed variables on four-component vector boundaries.");
return MergeResult.Failed; // don't merge matrix types
}
if (info.rows + merged.rows > 4)
{
// @TODO: lift the restriction
Error("can't merge '" + merged.DeclString() + "' and '" + info.DeclString() + "' because then " + info.name + " would cross register boundary. Consider reordering the fields so that none of them cross four-component vector boundaries when packed.");
return MergeResult.Failed; // out of space
}
if (info.rows + merged.rows > 4)
{
// @TODO: lift the restriction
Error("can't merge '" + merged.DeclString() + "' and '" + info.DeclString() + "' because then " + info.name + " would cross register boundary. Consider reordering the fields so that none of them cross four-component vector boundaries when packed.");
return MergeResult.Failed; // out of space
}
merged.rows += info.rows;
merged.name += "_" + info.name;
return MergeResult.Merged;
}
merged.rows += info.rows;
merged.name += "_" + info.name;
return MergeResult.Merged;
}
List<ShaderFieldInfo> Pack(List<ShaderFieldInfo> shaderFields)
{
List<ShaderFieldInfo> mergedFields = new List<ShaderFieldInfo>();
List<ShaderFieldInfo> Pack(List<ShaderFieldInfo> shaderFields)
{
List<ShaderFieldInfo> mergedFields = new List<ShaderFieldInfo>();
List<ShaderFieldInfo>.Enumerator e = shaderFields.GetEnumerator();
List<ShaderFieldInfo>.Enumerator e = shaderFields.GetEnumerator();
if (!e.MoveNext())
{
// Empty shader struct definition.
return shaderFields;
}
if (!e.MoveNext())
{
// Empty shader struct definition.
return shaderFields;
}
ShaderFieldInfo current = e.Current.Clone() as ShaderFieldInfo;
ShaderFieldInfo current = e.Current.Clone() as ShaderFieldInfo;
while (e.MoveNext())
{
while (true)
{
int offset = current.elementCount;
MergeResult result = PackFields(e.Current, ref current);
while (e.MoveNext())
{
while (true)
{
int offset = current.elementCount;
MergeResult result = PackFields(e.Current, ref current);
if (result == MergeResult.Failed)
{
return null;
}
else if (result == MergeResult.Full)
{
break;
}
if (result == MergeResult.Failed)
{
return null;
}
else if (result == MergeResult.Full)
{
break;
}
// merge accessors
Accessor acc = current.accessor;
// merge accessors
Accessor acc = current.accessor;
acc.name = current.name;
e.Current.accessor = acc;
e.Current.swizzleOffset += offset;
acc.name = current.name;
e.Current.accessor = acc;
e.Current.swizzleOffset += offset;
current.packed = e.Current.packed = true;
current.packed = e.Current.packed = true;
if (!e.MoveNext())
{
mergedFields.Add(current);
return mergedFields;
}
}
mergedFields.Add(current);
current = e.Current.Clone() as ShaderFieldInfo;
}
if (!e.MoveNext())
{
mergedFields.Add(current);
return mergedFields;
}
}
mergedFields.Add(current);
current = e.Current.Clone() as ShaderFieldInfo;
}
return mergedFields;
}
return mergedFields;
}
public string EmitTypeDecl()
{
string shaderText = string.Empty;
public string EmitTypeDecl()
{
string shaderText = string.Empty;
shaderText += "// Generated from " + type.FullName + "\n";
shaderText += "// PackingRules = " + attr.packingRules.ToString() + "\n";
shaderText += "struct " + type.Name + "\n";
shaderText += "{\n";
foreach (ShaderFieldInfo shaderFieldInfo in packedFields)
{
shaderText += "\t" + shaderFieldInfo.ToString() + "\n";
}
shaderText += "};\n";
shaderText += "// Generated from " + type.FullName + "\n";
shaderText += "// PackingRules = " + attr.packingRules.ToString() + "\n";
shaderText += "struct " + type.Name + "\n";
shaderText += "{\n";
foreach (ShaderFieldInfo shaderFieldInfo in packedFields)
{
shaderText += "\t" + shaderFieldInfo.ToString() + "\n";
}
shaderText += "};\n";
return shaderText;
}
return shaderText;
}
public string EmitAccessors()
{
string shaderText = string.Empty;
public string EmitAccessors()
{
string shaderText = string.Empty;
shaderText += "//\n";
shaderText += "// Accessors for " + type.FullName + "\n";
shaderText += "//\n";
foreach (var shaderField in shaderFields)
{
Accessor acc = shaderField.accessor;
string accessorName = shaderField.originalName;
accessorName = "Get" + char.ToUpper(accessorName[0]) + accessorName.Substring(1);
shaderText += "//\n";
shaderText += "// Accessors for " + type.FullName + "\n";
shaderText += "//\n";
foreach (var shaderField in shaderFields)
{
Accessor acc = shaderField.accessor;
string accessorName = shaderField.originalName;
accessorName = "Get" + char.ToUpper(accessorName[0]) + accessorName.Substring(1);
shaderText += shaderField.typeString + " " + accessorName + "(" + type.Name + " value)\n";
shaderText += "{\n";
shaderText += shaderField.typeString + " " + accessorName + "(" + type.Name + " value)\n";
shaderText += "{\n";
string swizzle = "";
string swizzle = "";
// @TODO: support matrix type packing?
if (shaderField.cols == 1) // @TEMP
{
// don't emit redundant swizzles
if (shaderField.originalName != acc.name)
{
swizzle = "." + "xyzw".Substring(shaderField.swizzleOffset, shaderField.elementCount);
}
}
// @TODO: support matrix type packing?
if (shaderField.cols == 1) // @TEMP
{
// don't emit redundant swizzles
if (shaderField.originalName != acc.name)
{
swizzle = "." + "xyzw".Substring(shaderField.swizzleOffset, shaderField.elementCount);
}
}
shaderText += "\treturn value." + acc.name + swizzle + ";\n";
shaderText += "}\n";
}
shaderText += "\treturn value." + acc.name + swizzle + ";\n";
shaderText += "}\n";
}
return shaderText;
}
return shaderText;
}
public string EmitDefines()
{
string shaderText = string.Empty;
public string EmitDefines()
{
string shaderText = string.Empty;
shaderText += "//\n";
shaderText += "// " + type.FullName + ": static fields\n";
shaderText += "//\n";
foreach (var def in statics)
{
shaderText += "#define " + def.Key + " (" + def.Value + ")\n";
}
shaderText += "//\n";
shaderText += "// " + type.FullName + ": static fields\n";
shaderText += "//\n";
foreach (var def in statics)
{
shaderText += "#define " + def.Key + " (" + def.Value + ")\n";
}
return shaderText;
}
return shaderText;
}
public string Emit()
{
return EmitDefines() + EmitTypeDecl() + EmitAccessors();
}
public string Emit()
{
return EmitDefines() + EmitTypeDecl() + EmitAccessors();
}
public bool Generate()
{
statics = new Dictionary<string, string>();
public bool Generate()
{
statics = new Dictionary<string, string>();
FieldInfo[] fields = type.GetFields();
shaderFields = new List<ShaderFieldInfo>();
FieldInfo[] fields = type.GetFields();
shaderFields = new List<ShaderFieldInfo>();
if (type.IsEnum)
{
foreach (var field in fields)
{
if (!field.IsSpecialName)
{
string name = field.Name;
for (int i = 1; i < name.Length; i++)
{
if (char.IsLower(name[i-1]) && char.IsUpper(name[i]))
{
// case switch, insert underscore
name = name.Insert(i, "_");
}
}
statics[(type.Name + "_" + name).ToUpper()] = field.GetRawConstantValue().ToString();
}
}
errors = null;
return true;
}
if (type.IsEnum)
{
foreach (var field in fields)
{
if (!field.IsSpecialName)
{
string name = field.Name;
for (int i = 1; i < name.Length; i++)
{
if (char.IsLower(name[i - 1]) && char.IsUpper(name[i]))
{
// case switch, insert underscore
name = name.Insert(i, "_");
}
}
statics[(type.Name + "_" + name).ToUpper()] = field.GetRawConstantValue().ToString();
}
}
errors = null;
return true;
}
foreach (var field in fields)
{
if (field.IsStatic)
{
if (field.FieldType.IsPrimitive)
{
statics[field.Name] = field.GetValue(null).ToString();
}
continue;
}
foreach (var field in fields)
{
if (field.IsStatic)
{
if (field.FieldType.IsPrimitive)
{
statics[field.Name] = field.GetValue(null).ToString();
}
continue;
}
if (attr.simple)
{
string subNamespace = type.Namespace.Substring(type.Namespace.LastIndexOf((".")) + 1);
statics["DEBUGVIEW_" + subNamespace.ToUpper() + "_" + type.Name.ToUpper() + "_" + field.Name.ToUpper()] = Convert.ToString(attr.debugCounterStart + debugCounter++);
}
if (attr.simple)
{
string subNamespace = type.Namespace.Substring(type.Namespace.LastIndexOf((".")) + 1);
statics["DEBUGVIEW_" + subNamespace.ToUpper() + "_" + type.Name.ToUpper() + "_" + field.Name.ToUpper()] = Convert.ToString(attr.debugCounterStart + debugCounter++);
}
if (field.FieldType.IsPrimitive)
{
if (field.FieldType == typeof(float))
EmitPrimitiveType(PrimitiveType.Float, 1, field.Name, "", shaderFields);
else if (field.FieldType == typeof(int))
EmitPrimitiveType(PrimitiveType.Int, 1, field.Name, "", shaderFields);
else if (field.FieldType == typeof(uint))
EmitPrimitiveType(PrimitiveType.UInt, 1, field.Name, "", shaderFields);
else
{
Error("unsupported field type '" + field.FieldType + "'");
return false;
}
}
else
{
// handle special types, otherwise try parsing the struct
if (field.FieldType == typeof(Vector2))
EmitPrimitiveType(PrimitiveType.Float, 2, field.Name, "", shaderFields);
else if (field.FieldType == typeof(Vector3))
EmitPrimitiveType(PrimitiveType.Float, 3, field.Name, "", shaderFields);
else if (field.FieldType == typeof(Vector4))
EmitPrimitiveType(PrimitiveType.Float, 4, field.Name, "", shaderFields);
else if (field.FieldType == typeof(Matrix4x4))
EmitMatrixType(PrimitiveType.Float, 4, 4, field.Name, "", shaderFields);
else if (!ExtractComplex(field, shaderFields))
{
// Error reporting done in ExtractComplex()
return false;
}
}
}
if (field.FieldType.IsPrimitive)
{
if (field.FieldType == typeof(float))
EmitPrimitiveType(PrimitiveType.Float, 1, field.Name, "", shaderFields);
else if (field.FieldType == typeof(int))
EmitPrimitiveType(PrimitiveType.Int, 1, field.Name, "", shaderFields);
else if (field.FieldType == typeof(uint))
EmitPrimitiveType(PrimitiveType.UInt, 1, field.Name, "", shaderFields);
else
{
Error("unsupported field type '" + field.FieldType + "'");
return false;
}
}
else
{
// handle special types, otherwise try parsing the struct
if (field.FieldType == typeof(Vector2))
EmitPrimitiveType(PrimitiveType.Float, 2, field.Name, "", shaderFields);
else if (field.FieldType == typeof(Vector3))
EmitPrimitiveType(PrimitiveType.Float, 3, field.Name, "", shaderFields);
else if (field.FieldType == typeof(Vector4))
EmitPrimitiveType(PrimitiveType.Float, 4, field.Name, "", shaderFields);
else if (field.FieldType == typeof(Matrix4x4))
EmitMatrixType(PrimitiveType.Float, 4, 4, field.Name, "", shaderFields);
else if (!ExtractComplex(field, shaderFields))
{
// Error reporting done in ExtractComplex()
return false;
}
}
}
packedFields = shaderFields;
if (attr.packingRules == PackingRules.Aggressive)
{
packedFields = Pack(shaderFields);
packedFields = shaderFields;
if (attr.packingRules == PackingRules.Aggressive)
{
packedFields = Pack(shaderFields);
if (packedFields == null)
{
return false;
}
}
if (packedFields == null)
{
return false;
}
}
errors = null;
return true;
}
errors = null;
return true;
}
public bool hasFields
{
get { return shaderFields.Count > 0; }
}
public bool hasFields
{
get { return shaderFields.Count > 0; }
}
public bool hasStatics
{
get { return statics.Count > 0; }
}
public bool hasStatics
{
get { return statics.Count > 0; }
}
public bool IsSimple()
{
return attr.simple;
}
public bool IsSimple()
{
return attr.simple;
}
public Type type;
public GenerateHLSL attr;
public int debugCounter;
public List<string> errors = null;
public Type type;
public GenerateHLSL attr;
public int debugCounter;
public List<string> errors = null;
Dictionary<string, string> statics;
List<ShaderFieldInfo> shaderFields;
List<ShaderFieldInfo> packedFields;
}
Dictionary<string, string> statics;
List<ShaderFieldInfo> shaderFields;
List<ShaderFieldInfo> packedFields;
}
}
正在加载...
取消
保存