浏览代码

Shader generator

To reflect a C# struct or class, attach the [GenerateHLSL] attribute to
it.  The optional packing parameter is PackingRules.Exact (default),
which emits the struct as is.  PackingRules.Aggressive will result in a
tight packing subject to some restrictions.  Static primitive fields are
emitted as #defines.
/main
vlad-andreev 8 年前
当前提交
84f60431
共有 16 个文件被更改,包括 1108 次插入0 次删除
  1. 9
      Assets/Editor.meta
  2. 9
      Assets/ShaderGenerator.meta
  3. 9
      Assets/Editor/Tests.meta
  4. 9
      Assets/Editor/Tests/ShaderGeneratorTests.meta
  5. 158
      Assets/Editor/Tests/ShaderGeneratorTests/ShaderGeneratorTests.cs
  6. 12
      Assets/Editor/Tests/ShaderGeneratorTests/ShaderGeneratorTests.cs.meta
  7. 326
      Assets/ShaderGenerator/CSharpToHLSL.cs
  8. 12
      Assets/ShaderGenerator/CSharpToHLSL.cs.meta
  9. 24
      Assets/ShaderGenerator/ICSharpCode.NRefactory.dll.meta
  10. 12
      Assets/ShaderGenerator/ShaderGeneratorMenu.cs.meta
  11. 516
      Assets/ShaderGenerator/ShaderTypeGeneration.cs
  12. 12
      Assets/ShaderGenerator/ShaderTypeGeneration.cs.meta

9
Assets/Editor.meta


fileFormatVersion: 2
guid: 54638db712cad6648a0c736eb6f3c872
folderAsset: yes
timeCreated: 1474982819
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

9
Assets/ShaderGenerator.meta


fileFormatVersion: 2
guid: 4545c8d908390cb4da76ded2ad888b12
folderAsset: yes
timeCreated: 1474558712
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

9
Assets/Editor/Tests.meta


fileFormatVersion: 2
guid: dbbd06f4a92d01145b4cfc6a86cf0531
folderAsset: yes
timeCreated: 1474995603
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

9
Assets/Editor/Tests/ShaderGeneratorTests.meta


fileFormatVersion: 2
guid: 552442937a683d2479830866e050b035
folderAsset: yes
timeCreated: 1474988761
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

158
Assets/Editor/Tests/ShaderGeneratorTests/ShaderGeneratorTests.cs


using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Reflection;
using UnityEngine;
using UnityEditor;
using UnityEngine.Rendering;
using UnityEngine.ScriptableRenderLoop;
using NUnit.Framework;
[TestFixture]
public class ShaderGeneratorTests
{
struct FailureTypes
{
// Non-primitive type in nested struct
internal struct NestedWithNonPrimitiveType
{
public struct Data
{
public string s;
}
public Data contents;
}
// Unsupported primitive type in nested struct
internal struct UnsupportedPrimitiveType
{
public struct Data
{
public IntPtr intPtr;
}
public Data contents;
}
// Mixed types in nested struct
internal struct MixedTypesInNestedStruct
{
public struct Data
{
public float f;
public int i;
}
public Data contents;
}
// More than 4 primitive fields in nested struct
internal struct TooManyFields
{
public struct Data
{
public float f1, f2, f3, f4, f5;
}
public Data contents;
}
// Merge failure due to incompatible types
internal struct MergeIncompatibleTypes
{
public float f;
public Vector2 v;
public int i;
}
// Merge failure due to register boundary crossing
internal struct MergeCrossBoundary
{
public Vector2 u;
public Vector3 v;
}
}
// @TODO: should probably switch to exceptions...
static bool HasErrorString(List<string> errors, string errorSubstring)
{
if (errors == null)
return false;
bool foundError = false;
foreach (var error in errors)
{
if (error.IndexOf(errorSubstring) >= 0)
{
foundError = true;
break;
}
}
return foundError;
}
[Test]
public void Fail_NestedWithNonPrimitiveType()
{
string source;
List<string> errors;
bool success = CSharpToHLSL.GenerateHLSL(typeof(FailureTypes.NestedWithNonPrimitiveType), new GenerateHLSL(PackingRules.Exact), out source, out errors);
Assert.IsFalse(success);
Assert.IsTrue(HasErrorString(errors, "contains a non-primitive field type"));
}
[Test]
public void Fail_UnsupportedPrimitiveType()
{
string source;
List<string> errors;
bool success = CSharpToHLSL.GenerateHLSL(typeof(FailureTypes.UnsupportedPrimitiveType), new GenerateHLSL(PackingRules.Exact), out source, out errors);
Assert.IsFalse(success);
Assert.IsTrue(HasErrorString(errors, "contains an unsupported field type"));
}
[Test]
public void Fail_MixedTypesInNestedStruct()
{
string source;
List<string> errors;
bool success = CSharpToHLSL.GenerateHLSL(typeof(FailureTypes.MixedTypesInNestedStruct), new GenerateHLSL(PackingRules.Exact), out source, out errors);
Assert.IsFalse(success);
Assert.IsTrue(HasErrorString(errors, "contains mixed basic types"));
}
[Test]
public void Fail_TooManyFields()
{
string source;
List<string> errors;
bool success = CSharpToHLSL.GenerateHLSL(typeof(FailureTypes.TooManyFields), new GenerateHLSL(PackingRules.Aggressive), out source, out errors);
Assert.IsFalse(success);
Assert.IsTrue(HasErrorString(errors, "more than 4 fields"));
}
[Test]
public void Fail_MergeIncompatibleTypes()
{
string source;
List<string> errors;
bool success = CSharpToHLSL.GenerateHLSL(typeof(FailureTypes.MergeIncompatibleTypes), new GenerateHLSL(PackingRules.Aggressive), out source, out errors);
Assert.IsFalse(success);
Assert.IsTrue(HasErrorString(errors, "incompatible types"));
}
[Test]
public void Fail_MergeCrossBoundary()
{
string source;
List<string> errors;
bool success = CSharpToHLSL.GenerateHLSL(typeof(FailureTypes.MergeCrossBoundary), new GenerateHLSL(PackingRules.Aggressive), out source, out errors);
Assert.IsFalse(success);
Assert.IsTrue(HasErrorString(errors, "cross register boundary"));
}
}

12
Assets/Editor/Tests/ShaderGeneratorTests/ShaderGeneratorTests.cs.meta


fileFormatVersion: 2
guid: 00fe79650bcedd740a7ea5e58e49ffa4
timeCreated: 1474988969
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

326
Assets/ShaderGenerator/CSharpToHLSL.cs


using System;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Visitors;
using ICSharpCode.NRefactory.Ast;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
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 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;
}
errors = gen.errors;
return success;
}
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());
foreach (var assembly in assemblyList)
{
Type[] types = assembly.GetExportedTypes();
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);
}
}
}
}
}
// 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);
}
// 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.WriteLine("//");
writer.WriteLine("// This file was automatically generated from " + it.Key + ". Please don't edit by hand.");
writer.WriteLine("//");
writer.WriteLine();
foreach (var gen in it.Value)
{
if (gen.hasStatics)
{
writer.WriteLine(gen.EmitDefines());
}
}
foreach (var gen in it.Value)
{
if (gen.hasFields)
{
writer.WriteLine(gen.EmitTypeDecl());
}
}
foreach (var gen in it.Value)
{
if (gen.hasFields)
{
writer.WriteLine(gen.EmitAccessors());
}
}
writer.WriteLine();
}
}
}
}
static Dictionary<string, ShaderTypeGenerator> m_typeName;
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));
foreach (var symbol in uniqueSymbols)
{
parser.Lexer.ConditionalCompilationSymbols.Add(symbol, string.Empty);
}*/
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);
if (data.generators.Count > 0)
m_sourceGenerators[fileName] = data.generators;
}
catch
{
// does NRefactory throw anything we can handle here?
throw;
}
}
}
static Dictionary<string, List<ShaderTypeGenerator>> m_sourceGenerators;
class VisitorData
{
public VisitorData()
{
currentNamespaces = new Stack<string>();
currentClasses = new Stack<string>();
generators = new List<ShaderTypeGenerator>();
}
public string GetTypePrefix()
{
string fullNamespace = string.Empty;
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;
}
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;
}
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;
}
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
{
// Structured types only
if (typeDeclaration.Type == ClassType.Class || typeDeclaration.Type == ClassType.Struct)
{
VisitorData visitorData = (VisitorData)data;
string name = visitorData.GetTypePrefix() + typeDeclaration.Name;
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();
}
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();
}
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();
foreach (var k in keysToRemove)
{
assemblies.Remove(GetName(k.FullName));
}
return assemblies;
}
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;
}
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 Dictionary<string, Assembly> assemblies;
}
};

12
Assets/ShaderGenerator/CSharpToHLSL.cs.meta


fileFormatVersion: 2
guid: 4ead049ece6638f43b01c36907c333d1
timeCreated: 1474983173
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

24
Assets/ShaderGenerator/ICSharpCode.NRefactory.dll.meta


fileFormatVersion: 2
guid: 8f17dd2cf32101e4f8cc2a071e57157e
timeCreated: 1474983477
licenseType: Pro
PluginImporter:
serializedVersion: 1
iconMap: {}
executionOrder: {}
isPreloaded: 0
platformData:
Any:
enabled: 1
settings: {}
Editor:
enabled: 0
settings:
DefaultValueInitialized: true
WindowsStoreApps:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

12
Assets/ShaderGenerator/ShaderGeneratorMenu.cs.meta


fileFormatVersion: 2
guid: 6445a8672591a4647839c57df79b857b
timeCreated: 1474558722
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

516
Assets/ShaderGenerator/ShaderTypeGeneration.cs


using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Visitors;
namespace UnityEngine.ScriptableRenderLoop
{
public enum PackingRules
{
Exact,
Aggressive
};
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class)]
public class GenerateHLSL : System.Attribute
{
public PackingRules packingRules;
public GenerateHLSL(PackingRules rules = PackingRules.Exact)
{
packingRules = rules;
}
}
internal class ShaderTypeGenerator
{
public ShaderTypeGenerator(Type type, GenerateHLSL attr)
{
this.type = type;
this.attr = attr;
}
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;
}
if (rows > 1)
{
text += rows.ToString();
if (cols > 1)
{
text += "x" + cols.ToString();
}
}
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;
}
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;
};
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 DeclString()
{
return PrimitiveToString(type, rows, cols) + " " + name;
}
public override string ToString()
{
string text = DeclString() + ";";
if (comment.Length > 0)
{
text += " // " + comment;
}
return text;
}
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 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);
}
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 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;
string fieldName = "'" + field.FieldType.Name + " " + field.Name + "'";
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 (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);
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.
}
return true;
}
enum MergeResult
{
Merged,
Full,
Failed
};
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.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
}
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>.Enumerator e = shaderFields.GetEnumerator();
if (!e.MoveNext())
{
// Empty shader struct definition.
return shaderFields;
}
ShaderFieldInfo current = e.Current.Clone() as ShaderFieldInfo;
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;
}
// merge accessors
Accessor acc = current.accessor;
acc.name = current.name;
e.Current.accessor = acc;
e.Current.swizzleOffset += offset;
current.packed = e.Current.packed = true;
if (!e.MoveNext())
{
mergedFields.Add(current);
return mergedFields;
}
}
mergedFields.Add(current);
current = e.Current.Clone() as ShaderFieldInfo;
}
return mergedFields;
}
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";
return shaderText;
}
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 += shaderField.typeString + " " + accessorName + "(" + type.Name + " value)\n";
shaderText += "{\n";
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);
}
}
shaderText += "\treturn value." + acc.name + swizzle + ";\n";
shaderText += "}\n";
}
return shaderText;
}
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";
}
return shaderText;
}
public string Emit()
{
return EmitDefines() + EmitTypeDecl() + EmitAccessors();
}
public bool Generate()
{
statics = new Dictionary<string, string>();
FieldInfo[] fields = type.GetFields();
shaderFields = new List<ShaderFieldInfo>();
foreach (var field in fields)
{
if (field.IsStatic)
{
if (field.FieldType.IsPrimitive)
{
statics[field.Name] = field.GetValue(null).ToString();
}
continue;
}
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);
if (packedFields == null)
{
return false;
}
}
errors = null;
return true;
}
public bool hasFields
{
get { return shaderFields.Count > 0; }
}
public bool hasStatics
{
get { return statics.Count > 0; }
}
public Type type;
public GenerateHLSL attr;
public List<string> errors = null;
Dictionary<string, string> statics;
List<ShaderFieldInfo> shaderFields;
List<ShaderFieldInfo> packedFields;
}
}

12
Assets/ShaderGenerator/ShaderTypeGeneration.cs.meta


fileFormatVersion: 2
guid: 7040da56d9fb04348885577a35fc0706
timeCreated: 1474983173
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存