private static VFXExpression PatchVFXExpression(VFXExpression input, 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;

                    default: break;
                    }
                }

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