123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using UnityEditor.VFX;
- using UnityEngine;
- using UnityEngine.VFX;
- using UnityObject = UnityEngine.Object;
- namespace UnityEditor.VFX
- {
- static class VFXReflectionHelper
- {
- public static T[] CollectStaticReadOnlyExpression<T>(Type expressionType, System.Reflection.BindingFlags additionnalFlag = System.Reflection.BindingFlags.Public)
- {
- var members = expressionType.GetFields(System.Reflection.BindingFlags.Static | additionnalFlag)
- .Where(m => m.IsInitOnly && m.FieldType == typeof(T))
- .ToArray();
- var expressions = members.Select(m => (T)m.GetValue(null)).ToArray();
- return expressions;
- }
- }
- abstract partial class VFXExpression
- {
- public struct Operands
- {
- public static readonly int OperandCount = 4;
- int data0;
- int data1;
- int data2;
- int data3;
- public Operands(int defaultValue)
- {
- data0 = defaultValue;
- data1 = defaultValue;
- data2 = defaultValue;
- data3 = defaultValue;
- }
- // This ugly code is for optimization purpose (no garbage created)
- public int this[int index]
- {
- get
- {
- switch (index)
- {
- case 0: return data0;
- case 1: return data1;
- case 2: return data2;
- case 3: return data3;
- default: throw new IndexOutOfRangeException();
- }
- }
- set
- {
- switch (index)
- {
- case 0: data0 = value; break;
- case 1: data1 = value; break;
- case 2: data2 = value; break;
- case 3: data3 = value; break;
- default: throw new IndexOutOfRangeException();
- }
- }
- }
- public int[] ToArray()
- {
- return new int[] { data0, data1, data2, data3 };
- }
- }
- [Flags]
- public enum Flags
- {
- None = 0,
- Value = 1 << 0, // Expression is a value, get/set can be called on it
- Foldable = 1 << 1, // Expression is not a constant but can be folded anyway
- Constant = 1 << 2, // Expression is a constant, it can be folded
- InvalidOnGPU = 1 << 3, // Expression can be evaluated on GPU
- InvalidOnCPU = 1 << 4, // Expression can be evaluated on CPU
- InvalidConstant = 1 << 5, // Expression can be folded (for UI) but constant folding is forbidden
- PerElement = 1 << 6, // Expression is per element
- PerSpawn = 1 << 7, // Expression relies on event attribute or spawn context
- NotCompilableOnCPU = InvalidOnCPU | PerElement //Helper to filter out invalid expression on CPU
- }
- public static bool IsFloatValueType(VFXValueType valueType)
- {
- return valueType == VFXValueType.Float
- || valueType == VFXValueType.Float2
- || valueType == VFXValueType.Float3
- || valueType == VFXValueType.Float4;
- }
- public static bool IsUIntValueType(VFXValueType valueType)
- {
- return valueType == VFXValueType.Uint32;
- }
- public static bool IsIntValueType(VFXValueType valueType)
- {
- return valueType == VFXValueType.Int32;
- }
- public static bool IsBoolValueType(VFXValueType valueType)
- {
- return valueType == VFXValueType.Boolean;
- }
- public static int TypeToSize(VFXValueType type)
- {
- return VFXExpressionHelper.GetSizeOfType(type);
- }
- public static string TypeToCode(VFXValueType type)
- {
- switch (type)
- {
- case VFXValueType.Float: return "float";
- case VFXValueType.Float2: return "float2";
- case VFXValueType.Float3: return "float3";
- case VFXValueType.Float4: return "float4";
- case VFXValueType.Int32: return "int";
- case VFXValueType.Uint32: return "uint";
- case VFXValueType.Texture2D: return "Texture2D";
- case VFXValueType.Texture2DArray: return "Texture2DArray";
- case VFXValueType.Texture3D: return "Texture3D";
- case VFXValueType.TextureCube: return "TextureCube";
- case VFXValueType.TextureCubeArray: return "TextureCubeArray";
- case VFXValueType.CameraBuffer: return "CameraBuffer";
- case VFXValueType.Matrix4x4: return "float4x4";
- case VFXValueType.Mesh:
- case VFXValueType.SkinnedMeshRenderer:
- case VFXValueType.Buffer: return "ByteAddressBuffer";
- case VFXValueType.Boolean: return "bool";
- }
- throw new NotImplementedException(type.ToString());
- }
- // As certain type of uniforms are not handled in material, we need to use floats instead
- public static string TypeToUniformCode(VFXValueType type)
- {
- switch (type)
- {
- case VFXValueType.Float: return "float";
- case VFXValueType.Float2: return "float2";
- case VFXValueType.Float3: return "float3";
- case VFXValueType.Float4: return "float4";
- case VFXValueType.Int32: return "float";
- case VFXValueType.Uint32: return "float";
- case VFXValueType.Matrix4x4: return "float4x4";
- case VFXValueType.Boolean: return "float";
- }
- throw new NotImplementedException(type.ToString());
- }
- public static Type TypeToType(VFXValueType type)
- {
- switch (type)
- {
- case VFXValueType.Float: return typeof(float);
- case VFXValueType.Float2: return typeof(Vector2);
- case VFXValueType.Float3: return typeof(Vector3);
- case VFXValueType.Float4: return typeof(Vector4);
- case VFXValueType.Int32: return typeof(int);
- case VFXValueType.Uint32: return typeof(uint);
- case VFXValueType.Texture2D: return typeof(Texture);
- case VFXValueType.Texture2DArray: return typeof(Texture);
- case VFXValueType.Texture3D: return typeof(Texture);
- case VFXValueType.TextureCube: return typeof(Texture);
- case VFXValueType.TextureCubeArray: return typeof(Texture);
- case VFXValueType.CameraBuffer: return typeof(CameraBuffer);
- case VFXValueType.Matrix4x4: return typeof(Matrix4x4);
- case VFXValueType.Mesh: return typeof(Mesh);
- case VFXValueType.Curve: return typeof(AnimationCurve);
- case VFXValueType.ColorGradient: return typeof(Gradient);
- case VFXValueType.Boolean: return typeof(bool);
- }
- throw new NotImplementedException(type.ToString());
- }
- public static bool IsTypeValidOnGPU(VFXValueType type)
- {
- switch (type)
- {
- case VFXValueType.Float:
- case VFXValueType.Float2:
- case VFXValueType.Float3:
- case VFXValueType.Float4:
- case VFXValueType.Int32:
- case VFXValueType.Uint32:
- case VFXValueType.Texture2D:
- case VFXValueType.Texture2DArray:
- case VFXValueType.Texture3D:
- case VFXValueType.TextureCube:
- case VFXValueType.TextureCubeArray:
- case VFXValueType.CameraBuffer:
- case VFXValueType.Matrix4x4:
- case VFXValueType.Boolean:
- return true;
- }
- return false;
- }
- public static bool IsTypeConstantFoldable(VFXValueType type)
- {
- switch (type)
- {
- //Mesh API can modify the vertex count & layout.
- //Thus, all mesh related expression should never been constant folded while generating code.
- // The same goes for textures
- case VFXValueType.Texture2D:
- case VFXValueType.Texture2DArray:
- case VFXValueType.Texture3D:
- case VFXValueType.TextureCube:
- case VFXValueType.TextureCubeArray:
- case VFXValueType.CameraBuffer:
- case VFXValueType.Mesh:
- case VFXValueType.SkinnedMeshRenderer:
- case VFXValueType.Buffer:
- return false;
- }
- return true;
- }
- public static bool IsTexture(Type type)
- {
- var valueType = GetVFXValueTypeFromType(type);
- return IsTexture(valueType);
- }
- public static bool IsTexture(VFXValueType type)
- {
- switch (type)
- {
- case VFXValueType.Texture2D:
- case VFXValueType.Texture2DArray:
- case VFXValueType.Texture3D:
- case VFXValueType.TextureCube:
- case VFXValueType.TextureCubeArray:
- case VFXValueType.CameraBuffer:
- return true;
- }
- return false;
- }
- public static bool IsBufferOnGPU(VFXValueType type)
- {
- return type == VFXValueType.Mesh || type == VFXValueType.Buffer;
- }
- public static bool IsUniform(VFXValueType type)
- {
- switch (type)
- {
- case VFXValueType.Float:
- case VFXValueType.Float2:
- case VFXValueType.Float3:
- case VFXValueType.Float4:
- case VFXValueType.Int32:
- case VFXValueType.Uint32:
- case VFXValueType.Matrix4x4:
- case VFXValueType.Boolean:
- return true;
- }
- return false;
- }
- public static Type GetMatchingScalar(Type type)
- {
- var vfxType = GetVFXValueTypeFromType(type);
- if (vfxType == VFXValueType.None)
- {
- var affinityFallback = VFXOperatorDynamicOperand.GetTypeAffinityList(type).GetEnumerator();
- while (affinityFallback.MoveNext() && vfxType == VFXValueType.None)
- {
- vfxType = GetVFXValueTypeFromType(affinityFallback.Current);
- }
- }
- return TypeToType(GetMatchingScalar(vfxType));
- }
- public static VFXValueType GetMatchingScalar(VFXValueType type)
- {
- if (IsFloatValueType(type))
- return VFXValueType.Float;
- if (IsUIntValueType(type))
- return VFXValueType.Uint32;
- if (IsIntValueType(type))
- return VFXValueType.Int32;
- return VFXValueType.None;
- }
- public static VFXValueType GetVFXValueTypeFromType(Type type)
- {
- if (type == typeof(float)) return VFXValueType.Float;
- if (type == typeof(Vector2)) return VFXValueType.Float2;
- if (type == typeof(Vector3)) return VFXValueType.Float3;
- if (type == typeof(Vector4)) return VFXValueType.Float4;
- if (type == typeof(Color)) return VFXValueType.Float4;
- if (type == typeof(int)) return VFXValueType.Int32;
- if (type == typeof(uint)) return VFXValueType.Uint32;
- if (type == typeof(Texture2D)) return VFXValueType.Texture2D;
- if (type == typeof(Texture2DArray)) return VFXValueType.Texture2DArray;
- if (type == typeof(Texture3D)) return VFXValueType.Texture3D;
- if (type == typeof(Cubemap)) return VFXValueType.TextureCube;
- if (type == typeof(CubemapArray)) return VFXValueType.TextureCubeArray;
- if (type == typeof(CameraBuffer)) return VFXValueType.CameraBuffer;
- if (type == typeof(Matrix4x4)) return VFXValueType.Matrix4x4;
- if (type == typeof(AnimationCurve)) return VFXValueType.Curve;
- if (type == typeof(Gradient)) return VFXValueType.ColorGradient;
- if (type == typeof(Mesh)) return VFXValueType.Mesh;
- if (type == typeof(SkinnedMeshRenderer)) return VFXValueType.SkinnedMeshRenderer;
- if (type == typeof(List<Vector3>)) return VFXValueType.Spline;
- if (type == typeof(bool)) return VFXValueType.Boolean;
- if (type == typeof(GraphicsBuffer)) return VFXValueType.Buffer;
- return VFXValueType.None;
- }
- private static Dictionary<VFXExpression, VFXExpression> s_ExpressionCache = new Dictionary<VFXExpression, VFXExpression>();
- public static void ClearCache()
- {
- s_ExpressionCache.Clear();
- }
- //Ideally, we should use HashSet<T>.TryGetValue https://msdn.microsoft.com/en-us/library/mt829070(v=vs.110).aspx
- //but it's available only in 4.7, Dictionary<T, T> is a workaround, sensible same performance but there is a waste of memory
- private void SimplifyWithCacheParents()
- {
- for (int i = 0; i < m_Parents.Length; ++i)
- {
- VFXExpression parentEq;
- if (!s_ExpressionCache.TryGetValue(parents[i], out parentEq))
- {
- s_ExpressionCache.Add(parents[i], parents[i]);
- }
- else
- {
- m_Parents[i] = parentEq;
- }
- }
- }
- protected VFXExpression(Flags flags, params VFXExpression[] parents)
- {
- if (parents.Length > 4)
- {
- throw new System.ArgumentException("An expression can only take up to 4 parent expressions");
- }
- m_Parents = parents;
- SimplifyWithCacheParents();
- m_Flags = flags;
- PropagateParentsFlags();
- }
- // Only do that when constructing an instance if needed
- private void Initialize(VFXExpression[] parents)
- {
- if (parents.Length > 4)
- {
- throw new System.ArgumentException("An expression can only take up to 4 parent expressions");
- }
- m_Parents = parents;
- SimplifyWithCacheParents();
- PropagateParentsFlags();
- m_HashCodeCached = false; // as expression is mutated
- }
- //Helper using reflection to recreate a concrete type from an abstract class (useful with reduce behavior)
- private static VFXExpression CreateNewInstance(Type expressionType)
- {
- var allconstructors = expressionType.GetConstructors().ToArray();
- if (allconstructors.Length == 0)
- return null; //Only static readonly expression allowed, constructors are private (attribute or builtIn)
- var constructor = allconstructors
- .OrderBy(o => o.GetParameters().Count()) //promote simplest (or default) constructors
- .First();
- var param = constructor.GetParameters().Select(o =>
- {
- var type = o.GetType();
- return type.IsValueType ? Activator.CreateInstance(type) : null;
- }).ToArray();
- return (VFXExpression)constructor.Invoke(param);
- }
- private VFXExpression CreateNewInstance()
- {
- return CreateNewInstance(GetType());
- }
- // Reduce the expression
- protected virtual VFXExpression Reduce(VFXExpression[] reducedParents)
- {
- if (reducedParents.Length == 0)
- return this;
- var reduced = CreateNewInstance();
- reduced.Initialize(reducedParents);
- return reduced;
- }
- // Evaluate the expression
- protected virtual VFXExpression Evaluate(VFXExpression[] constParents)
- {
- throw new NotImplementedException();
- }
- // Get the HLSL code snippet
- public virtual string GetCodeString(string[] parents)
- {
- throw new NotImplementedException(GetType().ToString());
- }
- // Get the operands for the runtime evaluation
- public Operands GetOperands(VFXExpressionGraph graph)
- {
- var addOperands = additionnalOperands;
- if (parents.Length + addOperands.Length > 4)
- throw new Exception("Too many parameters for expression : " + this);
- var data = new Operands(-1);
- if (graph != null)
- for (int i = 0; i < parents.Length; ++i)
- data[i] = graph.GetFlattenedIndex(parents[i]);
- for (int i = 0; i < addOperands.Length; ++i)
- data[Operands.OperandCount - addOperands.Length + i] = addOperands[i];
- return data;
- }
- public virtual IEnumerable<VFXAttributeInfo> GetNeededAttributes()
- {
- return Enumerable.Empty<VFXAttributeInfo>();
- }
- public bool Is(Flags flag) { return (m_Flags & flag) == flag; }
- public bool IsAny(Flags flag) { return (m_Flags & flag) != 0; }
- public virtual VFXValueType valueType
- {
- get
- {
- var data = GetOperands(null);
- return VFXExpressionHelper.GetTypeOfOperation(operation, data[0], data[1], data[2], data[3]);
- }
- }
- public abstract VFXExpressionOperation operation { get; }
- public VFXExpression[] parents { get { return m_Parents; } }
- public override bool Equals(object obj)
- {
- if (ReferenceEquals(this, obj))
- return true;
- var other = obj as VFXExpression;
- if (other == null)
- return false;
- if (GetType() != other.GetType())
- return false;
- if (operation != other.operation)
- return false;
- if (valueType != other.valueType)
- return false;
- if (m_Flags != other.m_Flags)
- return false;
- if (GetHashCode() != other.GetHashCode())
- return false;
- var operands = additionnalOperands;
- var otherOperands = other.additionnalOperands;
- if (operands.Length != otherOperands.Length)
- return false;
- for (int i = 0; i < operands.Length; ++i)
- if (operands[i] != otherOperands[i])
- return false;
- var thisParents = parents;
- var otherParents = other.parents;
- if (thisParents == null && otherParents == null)
- return true;
- if (thisParents == null || otherParents == null)
- return false;
- if (thisParents.Length != otherParents.Length)
- return false;
- for (int i = 0; i < thisParents.Length; ++i)
- if (!thisParents[i].Equals(otherParents[i]))
- return false;
- return true;
- }
- public override sealed int GetHashCode()
- {
- if (!m_HashCodeCached)
- {
- m_HashCode = GetInnerHashCode();
- m_HashCodeCached = true;
- }
- return m_HashCode;
- }
- protected virtual int GetInnerHashCode()
- {
- int hash = GetType().GetHashCode();
- var parents = this.parents;
- for (int i = 0; i < parents.Length; ++i)
- hash = (hash * 397) ^ parents[i].GetHashCode(); // 397 taken from resharper
- var operands = additionnalOperands;
- for (int i = 0; i < operands.Length; ++i)
- hash = (hash * 397) ^ operands[i].GetHashCode();
- hash = (hash * 397) ^ m_Flags.GetHashCode();
- hash = (hash * 397) ^ valueType.GetHashCode();
- hash = (hash * 397) ^ operation.GetHashCode();
- return hash;
- }
- private static readonly int[] k_EmptyOperands = Enumerable.Empty<int>().ToArray();
- protected virtual int[] additionnalOperands { get { return k_EmptyOperands; } }
- public virtual T Get<T>()
- {
- var value = (this as VFXValue<T>);
- if (value == null)
- {
- throw new ArgumentException(string.Format("Get isn't available for {0} with {1}", typeof(T).FullName, GetType().FullName));
- }
- return value.Get();
- }
- public virtual object GetContent()
- {
- throw new ArgumentException(string.Format("GetContent isn't available for {0}", GetType().FullName));
- }
- private void PropagateParentsFlags()
- {
- if (m_Parents.Length > 0)
- {
- bool foldable = true;
- foreach (var parent in m_Parents)
- {
- foldable &= parent.Is(Flags.Foldable);
- const Flags propagatedFlags = Flags.NotCompilableOnCPU | Flags.InvalidConstant | Flags.PerSpawn;
- m_Flags |= parent.m_Flags & propagatedFlags;
- if (parent.IsAny(Flags.NotCompilableOnCPU) && parent.Is(Flags.InvalidOnGPU))
- m_Flags |= Flags.InvalidOnGPU; // Only propagate GPU validity for per element expressions
- if (parent.Is(Flags.InvalidConstant))
- m_Flags |= Flags.InvalidConstant;
- }
- if (foldable)
- m_Flags |= Flags.Foldable;
- else
- m_Flags &= ~Flags.Foldable;
- }
- }
- public static VFXExpression operator *(VFXExpression a, VFXExpression b) { return new VFXExpressionMul(a, b); }
- public static VFXExpression operator /(VFXExpression a, VFXExpression b) { return new VFXExpressionDivide(a, b); }
- public static VFXExpression operator +(VFXExpression a, VFXExpression b) { return new VFXExpressionAdd(a, b); }
- public static VFXExpression operator -(VFXExpression a, VFXExpression b) { return new VFXExpressionSubtract(a, b); }
- public static VFXExpression operator |(VFXExpression a, VFXExpression b) { return new VFXExpressionBitwiseOr(a, b); }
- public static VFXExpression operator &(VFXExpression a, VFXExpression b) { return new VFXExpressionBitwiseAnd(a, b); }
- public static VFXExpression operator |(VFXExpression a, uint b) { return new VFXExpressionBitwiseOr(a, VFXValue.Constant(b)); }
- public static VFXExpression operator &(VFXExpression a, uint b) { return new VFXExpressionBitwiseAnd(a, VFXValue.Constant(b)); }
- public static VFXExpression operator <<(VFXExpression a, int shift) { return new VFXExpressionBitwiseLeftShift(a, VFXValue.Constant((uint)shift)); }
- public static VFXExpression operator >>(VFXExpression a, int shift) { return new VFXExpressionBitwiseRightShift(a, VFXValue.Constant((uint)shift)); }
- public VFXExpression this[int index] { get { return new VFXExpressionExtractComponent(this, index); } }
- public VFXExpression x { get { return new VFXExpressionExtractComponent(this, 0); } }
- public VFXExpression y { get { return new VFXExpressionExtractComponent(this, 1); } }
- public VFXExpression z { get { return new VFXExpressionExtractComponent(this, 2); } }
- public VFXExpression w { get { return new VFXExpressionExtractComponent(this, 3); } }
- public VFXExpression xxx { get { return new VFXExpressionCombine(x, x, x); } }
- public VFXExpression yyy { get { return new VFXExpressionCombine(y, y, y); } }
- public VFXExpression zzz { get { return new VFXExpressionCombine(z, z, z); } }
- private Flags m_Flags = Flags.None;
- private VFXExpression[] m_Parents;
- private int m_HashCode;
- private bool m_HashCodeCached = false;
- }
- }
|