123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- using System;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Linq;
- using UnityEngine.Profiling;
- using UnityEngine.VFX;
- namespace UnityEditor.VFX
- {
- [Flags]
- enum VFXExpressionContextOption
- {
- None = 0,
- Reduction = 1 << 0,
- CPUEvaluation = 1 << 1,
- ConstantFolding = 1 << 2,
- GPUDataTransformation = 1 << 3,
- PatchReadToEventAttribute = 1 << 4
- }
- abstract partial class VFXExpression
- {
- public class Context
- {
- private bool Has(VFXExpressionContextOption options)
- {
- return (m_ReductionOptions & options) == options;
- }
- private bool HasAny(VFXExpressionContextOption options)
- {
- return (m_ReductionOptions & options) != 0;
- }
- public Context(VFXExpressionContextOption reductionOption, List<VFXLayoutElementDesc> globalEventAttibutes = null)
- {
- m_ReductionOptions = reductionOption;
- m_GlobalEventAttribute = globalEventAttibutes;
- if (Has(VFXExpressionContextOption.CPUEvaluation) && Has(VFXExpressionContextOption.GPUDataTransformation))
- throw new ArgumentException("Invalid reduction options");
- }
- public void RegisterExpression(VFXExpression expression)
- {
- m_EndExpressions.Add(expression);
- }
- public void UnregisterExpression(VFXExpression expression)
- {
- Invalidate(expression);
- m_EndExpressions.Remove(expression);
- }
- public void Compile()
- {
- Profiler.BeginSample("VFXEditor.CompileExpressionContext");
- try
- {
- foreach (var exp in m_EndExpressions)
- Compile(exp);
- if (HasAny(VFXExpressionContextOption.GPUDataTransformation | VFXExpressionContextOption.PatchReadToEventAttribute))
- {
- var gpuTransformation = Has(VFXExpressionContextOption.GPUDataTransformation);
- var spawnEventPath = Has(VFXExpressionContextOption.PatchReadToEventAttribute);
- foreach (var exp in m_EndExpressions)
- m_ReducedCache[exp] = PatchVFXExpression(GetReduced(exp), null /* no source in end expression */, gpuTransformation, spawnEventPath, m_GlobalEventAttribute);
- }
- }
- finally
- {
- Profiler.EndSample();
- }
- }
- public void Recompile()
- {
- Invalidate();
- Compile();
- }
- private bool ShouldEvaluate(VFXExpression exp, VFXExpression[] reducedParents)
- {
- if (!HasAny(VFXExpressionContextOption.Reduction | VFXExpressionContextOption.CPUEvaluation | VFXExpressionContextOption.ConstantFolding))
- return false;
- if (exp.IsAny(Flags.NotCompilableOnCPU))
- return false;
- if (!Has(VFXExpressionContextOption.CPUEvaluation) && exp.IsAny(Flags.InvalidConstant))
- return false;
- if (!exp.Is(Flags.Value) && reducedParents.Length == 0) // not a value
- return false;
- Flags flag = Flags.Value;
- if (!Has(VFXExpressionContextOption.CPUEvaluation))
- flag |= Has(VFXExpressionContextOption.ConstantFolding) ? Flags.Foldable : Flags.Constant;
- if (exp.Is(Flags.Value) && ((exp.m_Flags & (flag | Flags.InvalidOnCPU)) != flag))
- return false;
- return reducedParents.All(e => (e.m_Flags & (flag | Flags.InvalidOnCPU)) == flag);
- }
- private VFXExpression PatchVFXExpression(VFXExpression input, VFXExpression targetExpression, bool insertGPUTransformation, bool patchReadAttributeForSpawn, IEnumerable<VFXLayoutElementDesc> globalEventAttribute)
- {
- if (insertGPUTransformation)
- {
- switch (input.valueType)
- {
- case VFXValueType.ColorGradient:
- input = new VFXExpressionBakeGradient(input);
- break;
- case VFXValueType.Curve:
- input = new VFXExpressionBakeCurve(input);
- break;
- case VFXValueType.Mesh:
- case VFXValueType.SkinnedMeshRenderer:
- if (targetExpression != null)
- {
- if (input.valueType == VFXValueType.Mesh)
- {
- switch (targetExpression.operation)
- {
- case VFXExpressionOperation.SampleMeshVertexFloat:
- case VFXExpressionOperation.SampleMeshVertexFloat2:
- case VFXExpressionOperation.SampleMeshVertexFloat3:
- case VFXExpressionOperation.SampleMeshVertexFloat4:
- case VFXExpressionOperation.SampleMeshVertexColor:
- var channelFormatAndDimensionAndStream = targetExpression.parents[2];
- channelFormatAndDimensionAndStream = Compile(channelFormatAndDimensionAndStream);
- if (!(channelFormatAndDimensionAndStream is VFXExpressionMeshChannelInfos))
- throw new InvalidOperationException("Unexpected type of expression in mesh sampling : " + channelFormatAndDimensionAndStream);
- input = new VFXExpressionVertexBufferFromMesh(input, channelFormatAndDimensionAndStream);
- break;
- case VFXExpressionOperation.SampleMeshIndex:
- input = new VFXExpressionIndexBufferFromMesh(input);
- break;
- default:
- throw new InvalidOperationException("Unexpected source operation for InsertGPUTransformation : " + targetExpression.operation);
- }
- }
- else //VFXValueType.SkinnedMeshRenderer
- {
- if (targetExpression is VFXExpressionSampleSkinnedMeshRendererFloat
- || targetExpression is VFXExpressionSampleSkinnedMeshRendererFloat2
- || targetExpression is VFXExpressionSampleSkinnedMeshRendererFloat3
- || targetExpression is VFXExpressionSampleSkinnedMeshRendererFloat4
- || targetExpression is VFXExpressionSampleSkinnedMeshRendererColor)
- {
- var channelFormatAndDimensionAndStream = targetExpression.parents[2];
- channelFormatAndDimensionAndStream = Compile(channelFormatAndDimensionAndStream);
- if (!(channelFormatAndDimensionAndStream is VFXExpressionMeshChannelInfos))
- throw new InvalidOperationException("Unexpected type of expression in skinned mesh sampling : " + channelFormatAndDimensionAndStream);
- input = new VFXExpressionVertexBufferFromSkinnedMeshRenderer(input, channelFormatAndDimensionAndStream);
- }
- else
- {
- throw new InvalidOperationException("Unexpected source operation for InsertGPUTransformation : " + targetExpression);
- }
- }
- } //else sourceExpression is null, we can't determine usage but it's possible if value is declared but not used.
- break;
- case VFXValueType.Buffer:
- {
- //Save expression usage for later HLSL shader generation
- if (targetExpression is VFXExpressionSampleBuffer)
- {
- var sampledType = (targetExpression as VFXExpressionSampleBuffer).GetSampledType();
- if (!m_GraphicsBufferUsageType.TryGetValue(input, out var registeredType))
- {
- m_GraphicsBufferUsageType.Add(input, sampledType);
- }
- else if (registeredType != sampledType)
- {
- throw new InvalidOperationException(string.Format("Diverging type usage for GraphicsBuffer : {0}, {1}", registeredType, sampledType));
- }
- }
- }
- break;
- default:
- //Nothing to patch on this type
- break;
- }
- if (input.valueType == VFXValueType.Buffer && targetExpression is VFXExpressionSampleBuffer)
- {
- if (!m_GraphicsBufferUsageType.ContainsKey(input))
- {
- m_GraphicsBufferUsageType.Add(input, (targetExpression as VFXExpressionSampleBuffer).GetSampledType());
- }
- }
- }
- if (patchReadAttributeForSpawn && input is VFXAttributeExpression)
- {
- var attribute = input as VFXAttributeExpression;
- if (attribute.attributeLocation == VFXAttributeLocation.Current)
- {
- if (globalEventAttribute == null)
- throw new InvalidOperationException("m_GlobalEventAttribute is null");
- var layoutDesc = globalEventAttribute.FirstOrDefault(o => o.name == attribute.attributeName);
- if (layoutDesc.name != attribute.attributeName)
- throw new InvalidOperationException("Unable to find " + attribute.attributeName + " in globalEventAttribute");
- input = new VFXReadEventAttributeExpression(attribute.attribute, layoutDesc.offset.element);
- }
- }
- return input;
- }
- public VFXExpression Compile(VFXExpression expression)
- {
- var gpuTransformation = Has(VFXExpressionContextOption.GPUDataTransformation);
- var patchReadAttributeForSpawn = Has(VFXExpressionContextOption.PatchReadToEventAttribute);
- VFXExpression reduced;
- if (!m_ReducedCache.TryGetValue(expression, out reduced))
- {
- var parents = expression.parents.Select(e =>
- {
- var parent = Compile(e);
- bool currentGPUTransformation = gpuTransformation
- && expression.IsAny(VFXExpression.Flags.NotCompilableOnCPU)
- && !parent.IsAny(VFXExpression.Flags.NotCompilableOnCPU);
- parent = PatchVFXExpression(parent, expression, currentGPUTransformation, patchReadAttributeForSpawn, m_GlobalEventAttribute);
- return parent;
- }).ToArray();
- if (ShouldEvaluate(expression, parents))
- {
- reduced = expression.Evaluate(parents);
- }
- else if (HasAny(VFXExpressionContextOption.Reduction | VFXExpressionContextOption.CPUEvaluation | VFXExpressionContextOption.ConstantFolding) || !parents.SequenceEqual(expression.parents))
- {
- reduced = expression.Reduce(parents);
- }
- else
- {
- reduced = expression;
- }
- m_ReducedCache[expression] = reduced;
- }
- return reduced;
- }
- public void Invalidate()
- {
- m_ReducedCache.Clear();
- m_GraphicsBufferUsageType.Clear();
- }
- public void Invalidate(VFXExpression expression)
- {
- m_ReducedCache.Remove(expression);
- }
- public VFXExpression GetReduced(VFXExpression expression)
- {
- VFXExpression reduced;
- m_ReducedCache.TryGetValue(expression, out reduced);
- return reduced != null ? reduced : expression;
- }
- private void AddReducedGraph(HashSet<VFXExpression> dst, VFXExpression exp)
- {
- if (!dst.Contains(exp))
- {
- dst.Add(exp);
- foreach (var parent in exp.parents)
- AddReducedGraph(dst, parent);
- }
- }
- public HashSet<VFXExpression> BuildAllReduced()
- {
- var reduced = new HashSet<VFXExpression>();
- foreach (var exp in m_EndExpressions)
- if (m_ReducedCache.ContainsKey(exp))
- AddReducedGraph(reduced, m_ReducedCache[exp]);
- return reduced;
- }
- public ReadOnlyCollection<VFXExpression> RegisteredExpressions { get { return m_EndExpressions.ToList().AsReadOnly(); } }
- public IEnumerable<KeyValuePair<VFXExpression, Type>> GraphicsBufferUsageType { get { return m_GraphicsBufferUsageType; } }
- private Dictionary<VFXExpression, VFXExpression> m_ReducedCache = new Dictionary<VFXExpression, VFXExpression>();
- private HashSet<VFXExpression> m_EndExpressions = new HashSet<VFXExpression>();
- private Dictionary<VFXExpression, Type> m_GraphicsBufferUsageType = new Dictionary<VFXExpression, Type>();
- private IEnumerable<VFXLayoutElementDesc> m_GlobalEventAttribute;
- private VFXExpressionContextOption m_ReductionOptions;
- }
- }
- }
|