void ProcessValues(ref StageValue obj, out MetaStage minStage, out MetaStage maxStage, Expression inArg, out Expression outArg) { minStage = obj.MinStage; maxStage = obj.MaxStage; var stageArg = ProcessValue(inArg); if (stageArg.MinStage > minStage) { minStage = stageArg.MinStage; } if (stageArg.MaxStage < maxStage) { maxStage = stageArg.MaxStage; } if (maxStage < minStage) { maxStage = minStage; } outArg = ProcessStage(stageArg, minStage, maxStage).Value; obj = ProcessStage(obj, minStage, maxStage); }
Expression ProcessVertexBuffer(StageValue vertexBuffer) { Expression result; if (!VertexBuffers.TryGetValue(vertexBuffer.Value.ToString(), out result)) { var src = vertexBuffer.Value.Source; var type = ILFactory.GetType(src, "Uno.Graphics.VertexBuffer"); if (vertexBuffer.Value.ReturnType.Equals(type)) { result = ProcessStage(vertexBuffer, MetaStage.Volatile, MetaStage.Volatile).Value; VertexBuffers.Add(vertexBuffer.Value.ToString(), result); return(result); } var loc = LocationStack.Last(); var mp = GetProperty(loc); var name = CreateFieldName(mp, loc); var owner = Path.DrawBlock.Method.DeclaringType; var field = new Field(src, owner, name, null, Modifiers.Private | Modifiers.Generated, 0, type); owner.Fields.Add(field); result = new LoadField(src, new This(src, owner), field); VertexBuffers.Add(vertexBuffer.Value.ToString(), result); if (vertexBuffer.MinStage > MetaStage.Volatile) { Log.Error(src, ErrorCode.E5025, "Vertex buffer cannot be accessed from " + vertexBuffer.MinStage + " stage"); return(result); } else if (vertexBuffer.MinStage == MetaStage.Volatile) { InitScope.Statements.Add( new StoreField(src, new This(src, owner), field, ILFactory.NewObject(src, "Uno.Graphics.VertexBuffer", ILFactory.GetExpression(src, "Uno.Graphics.BufferUsage.Dynamic")))); FrameScope.Statements.Add( ILFactory.CallMethod(src, new LoadField(src, new This(src, owner), field), "Update", vertexBuffer.Value)); } else { InitScope.Statements.Add( new StoreField(src, new This(src, owner), field, ILFactory.NewObject(src, "Uno.Graphics.VertexBuffer", vertexBuffer.Value, ILFactory.GetExpression(src, "Uno.Graphics.BufferUsage.Immutable")))); } FreeScope.Statements.Add( ILFactory.CallMethod(src, new LoadField(src, new This(src, owner), field), "Dispose")); } return(result); }
void DetectVertexCount(StageValue buffer) { foreach (var p in buffer.Value.ReturnType.Properties) { if (p.UnoName == "Length") { AddDetectedVertexCount(new StageValue(new GetProperty(buffer.Value.Source, buffer.Value, p), buffer.MinStage, buffer.MaxStage)); return; } } }
void AddDetectedVertexCount(StageValue c) { var key = c.Value.ToString(); foreach (var d in DetectedVertexCounts) { if (d.Value.ToString() == key) { return; } } DetectedVertexCounts.Add(c); }
StageValue ProcessShaderConstant(StageValue s, MetaLocation loc, MetaProperty mp) { s = ProcessStage(s, MetaStage.Volatile, MetaStage.Volatile); var key = s.Value.ToString(); int index; if (!Constants.TryGetValue(key, out index)) { index = DrawState.RuntimeConstants.Count; DrawState.RuntimeConstants.Add(new ShaderVariable(s.Value.ReturnType, CreateShaderName(mp, loc, s.Value), s.Value)); Constants.Add(key, index); } return(new StageValue(new RuntimeConst(s.Value.Source, DrawState, index), MetaStage.Vertex, MetaStage.Pixel)); }
void AdjustFunctionStageRange(ref StageValue obj, Function func) { // TODO: Implement code analyzer to make sure func will work in shader or not if (obj.MaxStage >= MetaStage.Volatile && !Backend.ShaderBackend.IsIntrinsic(func) && func.Body == null) { obj.MaxStage = MetaStage.Volatile; } var shaderStageObj = func.TryGetAttribute(Essentials.RequireShaderStageAttribute); if (shaderStageObj != null) { obj.MinStage = obj.MaxStage = (MetaStage)(int)shaderStageObj; } }
internal StageValue ProcessStage(StageValue sym, MetaStage min, MetaStage max) { var loc = LocationStack.Last(); var mp = GetProperty(loc); if (max < sym.MinStage) { Log.Error(sym.Value.Source, ErrorCode.E5015, sym.MinStage.ToLiteral().Quote() + " cannot be accessed from stage " + max.ToLiteral().Quote() + " while processing " + mp.Name.Quote() + " at " + mp.Source + " in " + Path.Quote() + " at " + Path.Source); return(new StageValue(Expression.Invalid, MetaStage.Const)); } // Handle stage change if necessary or default to lowest possible stage if (min > sym.MaxStage || min > sym.MinStage && sym.Value != null && !InlineOnStage(min, sym.Value)) { return(ProcessStageChange(sym, sym.MinStage, min, loc, mp)); } return(sym); }
StageValue ProcessFixedArrayDeclaration(FixedArrayDeclaration s) { Expression[] initializer = null; var minStage = MetaStage.Const; var maxStage = MetaStage.Max; if (s.OptionalInitializer != null) { var stageValues = new StageValue[s.OptionalInitializer.Length]; for (int i = 0; i < stageValues.Length; i++) { var v = stageValues[i] = ProcessValue(s.OptionalInitializer[i]); if (v.MinStage > minStage) { minStage = v.MinStage; } if (v.MaxStage < maxStage) { maxStage = v.MaxStage; } } initializer = new Expression[stageValues.Length]; if (maxStage < minStage) { maxStage = minStage; } for (int i = 0; i < stageValues.Length; i++) { initializer[i] = ProcessStage(stageValues[i], minStage, maxStage).Value; } } return(new StageValue(new PlaceholderArray(s.Source, s.Variable.ValueType, initializer), minStage, maxStage)); }
void AdjustInstanceStageRange(ref StageValue obj, DataType dt, bool isFieldOrPropertyAccess) { // Default volatile on static members and current class members if (obj.MaxStage >= MetaStage.Volatile && (obj.Value == null || obj.Value.ActualValue is This || obj.Value.ActualValue is Base) && (obj.Value != null || isFieldOrPropertyAccess)) { obj.MinStage = MetaStage.Volatile; } if (isFieldOrPropertyAccess && !Backend.ShaderBackend.IsIntrinsic(dt)) { obj.MaxStage = MetaStage.Volatile; } var shaderStageObj = dt.TryGetAttribute(Essentials.RequireShaderStageAttribute); if (shaderStageObj != null) { obj.MinStage = obj.MaxStage = (MetaStage)(int)shaderStageObj; } }
void ProcessIndexBuffer(Source vaSrc, StageValue indexBuffer, StageValue indexType) { if (IndexBuffer == null && indexBuffer.Value == null && IndexType == null && indexType.Value == null || indexBuffer.Value != null && IndexBuffer == indexBuffer.Value.ToString() && indexType.Value != null && IndexType == indexType.Value.ToString()) { // OK return; } if (IndexBuffer != null || indexBuffer.Value == null || IndexType != null || indexType.Value == null) { Log.Error(vaSrc, ErrorCode.E5023, "Index buffer argument must be consistent for all <vertex_attrib>s in " + Path.Quote()); return; } var src = indexBuffer.Value.Source; var type = ILFactory.GetType(src, "Uno.Graphics.IndexBuffer"); IndexBuffer = indexBuffer.Value.ToString(); IndexType = indexType.Value.ToString(); if (indexBuffer.Value.ReturnType.Equals(type)) { DrawState.OptionalIndices = new IndexBinding( ProcessStage(indexType, MetaStage.Volatile, MetaStage.Volatile).Value, ProcessStage(indexBuffer, MetaStage.Volatile, MetaStage.Volatile).Value); return; } var loc = LocationStack.Last(); var mp = GetProperty(loc); var name = CreateFieldName(mp, loc); var owner = Path.DrawBlock.Method.DeclaringType; var field = new Field(src, owner, name, null, Modifiers.Private | Modifiers.Generated, 0, type); owner.Fields.Add(field); DrawState.OptionalIndices = new IndexBinding( ProcessStage(indexType, MetaStage.Volatile, MetaStage.Volatile).Value, new LoadField(src, new This(src, owner), field)); if (indexBuffer.MinStage > MetaStage.Volatile) { Log.Error(src, ErrorCode.E5024, "Index buffer cannot be accessed from " + indexBuffer.MinStage + " stage"); return; } if (indexBuffer.MinStage == MetaStage.Volatile) { InitScope.Statements.Add( new StoreField(src, new This(src, owner), field, ILFactory.NewObject(src, "Uno.Graphics.IndexBuffer", ILFactory.GetExpression(src, "Uno.Graphics.BufferUsage.Dynamic")))); FrameScope.Statements.Add( ILFactory.CallMethod(src, new LoadField(src, new This(src, owner), field), "Update", indexBuffer.Value)); } else { InitScope.Statements.Add( new StoreField(src, new This(src, owner), field, ILFactory.NewObject(src, "Uno.Graphics.IndexBuffer", indexBuffer.Value, ILFactory.GetExpression(src, "Uno.Graphics.BufferUsage.Immutable")))); } FreeScope.Statements.Add( ILFactory.CallMethod(src, new LoadField(src, new This(src, owner), field), "Dispose")); }
StageValue ProcessMetaProperty(MetaLocation loc, bool required = true) { StageValue result; if (ProcessedMetaProperties.TryGetValue(loc, out result)) { return(new StageValue(result.Value.CopyExpression(new CopyState(DrawState.Path.DrawBlock.Method)), result.MinStage, result.MaxStage)); } var mp = GetProperty(loc); var def = GetValidDefinition(loc); if (def == null) { if (required) { Log.Error(CreateTrace(mp, loc, null), ErrorCode.E5004, "No valid definition of " + mp.Name.Quote() + " was found in " + Path.Quote()); return(new StageValue(Expression.Invalid, MetaStage.Const)); } return(new StageValue(null, MetaStage.Const)); } // Detect circular references (should not happen) foreach (var ploc in LocationStack) { if (ploc == loc) { Log.Error(CreateTrace(mp, loc, LocationStack), ErrorCode.E5005, "Circular reference to " + mp.Name.Quote() + " detected while processing " + Path.Quote()); return(new StageValue(Expression.Invalid, MetaStage.Const)); } } LocationStack.Add(loc); switch (def.Value.StatementType) { case StatementType.Expression: result = ProcessValue(def.Value as Expression); result.Value = new FunctionCompiler(Compiler, mp).CompileImplicitCast(def.Value.Source, mp.ReturnType, result.Value); break; case StatementType.Scope: result = ScopeProcessor.Process(this, def.Value as Scope); break; case StatementType.FixedArrayDeclaration: result = ProcessFixedArrayDeclaration(def.Value as FixedArrayDeclaration); break; default: // Should not happen Log.Error(def.Value.Source, ErrorCode.I5006, "<" + def.Value.StatementType + "> is not supported by ShaderGenerator"); result = new StageValue(Expression.Invalid, MetaStage.Const); ProcessedMetaProperties.Add(loc, result); return(result); } LocationStack.RemoveLast(); if (!InlineOnStage(result.MinStage, result.Value)) { MetaStage resultStage; Scope resultScope; switch (result.MinStage) { case MetaStage.Pixel: resultStage = MetaStage.Pixel; resultScope = PixelScope; break; case MetaStage.Vertex: resultStage = MetaStage.Vertex; resultScope = VertexScope; break; case MetaStage.Volatile: resultStage = MetaStage.Volatile; resultScope = FrameScope; break; default: resultStage = MetaStage.ReadOnly; resultScope = InitScope; break; } var val = new PlaceholderValue(mp, loc, result.Value, resultStage); result = new StageValue(new PlaceholderReference(val), val.Stage); resultScope.Statements.Add(new VariableDeclaration(mp.Source, null, CreateLocalName(mp, loc), val.ReturnType, VariableType.Default, val)); } else if (!(result.Value is PlaceholderReference) && !(result.Value is PlaceholderValue) && !(result.Value is Constant)) { result.Value = new PlaceholderValue(mp, loc, result.Value, MetaStage.Undefined); } ProcessedMetaProperties.Add(loc, result); return(result); }
internal StageValue ProcessStageChange(StageValue s, MetaStage fromStage, MetaStage toStage, MetaLocation loc, MetaProperty mp) { if (s.Value == null) { return(new StageValue(null, toStage)); } if (s.MinStage > fromStage) { Log.Error(s.Value.Source, ErrorCode.I5016, "Stage error"); return(new StageValue(Expression.Invalid, toStage)); } switch (toStage) { case MetaStage.Pixel: case MetaStage.Vertex: if (fromStage == MetaStage.Vertex && toStage == MetaStage.Pixel) { // Vertex -> Pixel: Varying var key = s.Value.ToString(); int index; if (!Varyings.TryGetValue(key, out index)) { index = DrawState.Varyings.Count; DrawState.Varyings.Add(new ShaderVariable(s.Value.ReturnType, CreateShaderName(mp, loc, s.Value), s.Value)); Varyings.Add(key, index); } return(new StageValue(new LoadVarying(s.Value.Source, DrawState, index), MetaStage.Pixel, MetaStage.Pixel)); } else if (s.Value.ReturnType == Essentials.Bool || s.Value.ReturnType == Essentials.Int) { return(ProcessShaderConstant(s, loc, mp)); } else { // Init,Frame -> Vertex,Pixel: Uniform s = ProcessStage(s, MetaStage.Volatile, MetaStage.Volatile); var val = s.Value.ActualValue; var dt = val.ReturnType; var key = val.ToString(); int index; if (!Uniforms.TryGetValue(key, out index)) { index = DrawState.Uniforms.Count; switch (dt.TypeType) { case TypeType.FixedArray: // Ugly workaround. ResolvedMetaPropertyValue could already be an address if (!(val is PlaceholderValue && (val as PlaceholderValue).Value is AddressOf)) { val = new AddressOf(val.ActualValue, AddressType.Const); } break; case TypeType.RefArray: var at = dt as RefArrayType; var et = at.ElementType; var size = ProcessShaderConstant( new StageValue(ILFactory.GetProperty(s.Value.Source, s.Value, "Length"), s.MinStage, s.MaxStage), loc, mp).Value; dt = new FixedArrayType(s.Value.Source, et, size, Essentials.Int); break; } DrawState.Uniforms.Add(new ShaderVariable(dt, CreateShaderName(mp, loc, val), val)); Uniforms.Add(key, index); } Expression u = new LoadUniform(s.Value.Source, DrawState, index); if (u.ReturnType.IsFixedArray) { u = new AddressOf(u, AddressType.Const); } return(new StageValue(u, MetaStage.Vertex, MetaStage.Pixel)); } case MetaStage.Volatile: if (fromStage <= MetaStage.ReadOnly) { // Init -> Frame: Field var src = s.Value.Source; var dt = Path.DrawBlock.Method.DeclaringType; var obj = new This(src, dt).Address; var key = s.Value.ToString(); Field field; if (!Fields.TryGetValue(key, out field)) { for (int i = 0; i < InitScope.Statements.Count; i++) { if (InitScope.Statements[i] is StoreField) { var sf = InitScope.Statements[i] as StoreField; if (sf.Field.ReturnType.Equals(s.Value.ReturnType) && sf.Value.ToString() == key) { field = sf.Field; } } } if (field == null) { field = new Field(src, dt, CreateFieldName(mp, loc, s.Value), null, Modifiers.Private | Modifiers.Generated, 0, s.Value.ReturnType); dt.Fields.Add(field); InitScope.Statements.Add(new StoreField(src, obj, field, s.Value)); } Fields.Add(key, field); } return(new StageValue(new LoadField(src, obj, field), MetaStage.ReadOnly, MetaStage.Volatile)); } break; case MetaStage.ReadOnly: return(s); } Log.Error(s.Value.Source, ErrorCode.E5017, fromStage.ToLiteral().Quote() + " cannot be accessed from " + toStage.ToLiteral() + " stage while processing " + mp.Name.Quote() + " at " + mp.Source + " in " + Path.Quote() + " at " + Path.Source); return(new StageValue(Expression.Invalid, MetaStage.Const)); }
internal StageValue ProcessValue(Expression e) { if (e == null) { return(new StageValue(null, MetaStage.Const)); } switch (e.ExpressionType) { case ExpressionType.StageOp: { var s = e as StageOp; var op = ProcessValue(s.Operand); if (s.Stage > MetaStage.Volatile) { op = ProcessStage(op, s.Stage, s.Stage); } else if (op.MinStage > MetaStage.Volatile) { Log.Error(s.Operand.Source, ErrorCode.E0000, "Invalid " + s.Stage.ToLiteral() + " expression in " + Path.Quote()); return(new StageValue(Expression.Invalid, s.Stage, s.Stage)); } op.MinStage = s.Stage; return(op); } case ExpressionType.NewVertexAttrib: return(ProcessVertexAttrib(e as NewVertexAttrib)); case ExpressionType.NewPixelSampler: return(ProcessPixelSampler(e as NewPixelSampler)); case ExpressionType.GetMetaProperty: { var s = e as GetMetaProperty; var loc = TryGetLocation(LocationStack.Last(), s.Name, s.Offset); if (loc == null) { if (s.Offset == 0) { Log.Error(s.Source, ErrorCode.E5019, s.Name.Quote() + " was not found in " + Path.Quote()); } else { Log.Error(s.Source, ErrorCode.E5020, "Previous declaration of " + s.Name.Quote() + " was not found in " + Path.Quote()); } return(new StageValue(Expression.Invalid, MetaStage.Const)); } return(ProcessMetaProperty(loc.Value)); } case ExpressionType.GetMetaObject: { var s = e as GetMetaObject; var obj = TryGetObject(LocationStack.Last()); if (obj == null || !obj.ReturnType.IsSubclassOfOrEqual(s.ReturnType)) { Log.Error(s.Source, ErrorCode.E0000, "Unable to resolve instance of " + s.ReturnType.Quote() + " in " + Path.Quote()); } var objStage = ProcessValue(obj); return(new StageValue(objStage.Value, objStage.MinStage, objStage.MaxStage)); } case ExpressionType.Invalid: case ExpressionType.Constant: case ExpressionType.Default: case ExpressionType.ExternOp: case ExpressionType.ExternString: return(new StageValue(e, MetaStage.Const)); case ExpressionType.This: case ExpressionType.Base: case ExpressionType.TypeOf: return(new StageValue(e, MetaStage.ReadOnly, MetaStage.Volatile)); case ExpressionType.CapturedArgument: case ExpressionType.CapturedLocal: case ExpressionType.LoadArgument: return(new StageValue(e, MetaStage.Volatile, MetaStage.Volatile)); case ExpressionType.RuntimeConst: return(new StageValue(e, MetaStage.Vertex, MetaStage.Pixel)); case ExpressionType.LoadUniform: return(new StageValue(e, MetaStage.Vertex, MetaStage.Pixel)); case ExpressionType.LoadVarying: return(new StageValue(e, MetaStage.Pixel, MetaStage.Pixel)); case ExpressionType.LoadVertexAttrib: return(new StageValue(e, MetaStage.Vertex, MetaStage.Vertex)); case ExpressionType.FixOp: { var s = e as FixOp; var ps = ProcessValue(s.Operand); return(new StageValue(new FixOp(s.Source, s.Operator, ps.Value), ps.MinStage, ps.MaxStage)); } case ExpressionType.AddressOf: { var s = e as AddressOf; var ps = ProcessValue(s.Operand); return(new StageValue(new AddressOf(ps.Value, s.AddressType), ps.MinStage, ps.MaxStage)); } case ExpressionType.BranchOp: { var s = e as BranchOp; Expression left, right; MetaStage minStage, maxStage; ProcessValues(out minStage, out maxStage, s.Left, out left, s.Right, out right); return(new StageValue(new BranchOp(s.Source, s.ReturnType, s.BranchType, left, right), minStage, maxStage)); } case ExpressionType.ReferenceOp: { var s = e as ReferenceOp; Expression left, right; MetaStage minStage, maxStage; ProcessValues(out minStage, out maxStage, s.Left, out left, s.Right, out right); return(new StageValue(new ReferenceOp(s.Source, s.ReturnType, s.EqualityType, left, right), minStage, maxStage)); } case ExpressionType.SequenceOp: { var s = e as SequenceOp; Expression left, right; MetaStage minStage, maxStage; ProcessValues(out minStage, out maxStage, s.Left, out left, s.Right, out right); return(new StageValue(new SequenceOp(left, right), minStage, maxStage)); } case ExpressionType.ConditionalOp: { var s = e as ConditionalOp; var ps = ProcessValue(s.Condition); Expression a, b; MetaStage minStage, maxStage; ProcessValues(ref ps, out minStage, out maxStage, s.True, out a, s.False, out b); return(new StageValue(new ConditionalOp(s.Source, ps.Value, a, b), minStage, maxStage)); } case ExpressionType.NullOp: { var s = e as NullOp; var ps = StageValue.Default; if (ps.MaxStage > MetaStage.Volatile) { ps.MaxStage = MetaStage.Volatile; } Expression left, right; MetaStage minStage, maxStage; ProcessValues(ref ps, out minStage, out maxStage, s.Left, out left, s.Right, out right); return(new StageValue(new NullOp(s.Source, left, right), minStage, maxStage)); } case ExpressionType.IsOp: { var s = e as IsOp; var ps = ProcessValue(s.Operand); if (ps.MaxStage > MetaStage.Volatile) { ps.MaxStage = MetaStage.Volatile; } return(new StageValue(new IsOp(s.Source, ps.Value, s.TestType, s.ReturnType), ps.MinStage, ps.MaxStage)); } case ExpressionType.AsOp: { var s = e as AsOp; var ps = ProcessValue(s.Operand); if (ps.MaxStage > MetaStage.Volatile) { ps.MaxStage = MetaStage.Volatile; } return(new StageValue(new AsOp(s.Source, ps.Value, s.ReturnType), ps.MinStage, ps.MaxStage)); } case ExpressionType.LoadField: { var s = e as LoadField; var ps = ProcessValue(s.Object); AdjustInstanceStageRange(ref ps, s.Field.DeclaringType, true); return(new StageValue(new LoadField(s.Source, ps.Value, s.Field), ps.MinStage, ps.MaxStage)); } case ExpressionType.LoadElement: { var s = e as LoadElement; var ps = ProcessValue(s.Array); Expression index; MetaStage minStage, maxStage; ProcessValues(ref ps, out minStage, out maxStage, s.Index, out index); return(new StageValue(new LoadElement(s.Source, ps.Value, index), minStage, maxStage)); } case ExpressionType.Swizzle: { var s = e as Swizzle; var ps = ProcessValue(s.Object); AdjustInstanceStageRange(ref ps, s.Object.ReturnType, true); return(new StageValue(new Swizzle(s.Source, s.Constructor, ps.Value, s.Fields), ps.MinStage, ps.MaxStage)); } case ExpressionType.GetProperty: { var s = e as GetProperty; var ps = ProcessValue(s.Object); AdjustInstanceStageRange(ref ps, s.Property.DeclaringType, true); AdjustFunctionStageRange(ref ps, s.Property.GetMethod); MetaStage minStage, maxStage; var args = ProcessValues(ref ps, out minStage, out maxStage, s.Arguments); return(new StageValue(new GetProperty(s.Source, ps.Value, s.Property, args), minStage, maxStage)); } case ExpressionType.NewObject: { var s = e as NewObject; var ps = new StageValue(null, MetaStage.ReadOnly, s.ReturnType.IsReferenceType ? MetaStage.Volatile : MetaStage.Max); AdjustFunctionStageRange(ref ps, s.Constructor); MetaStage minStage, maxStage; var args = ProcessValues(ref ps, out minStage, out maxStage, s.Arguments); return(new StageValue(new NewObject(s.Source, s.Constructor, args), minStage, maxStage)); } case ExpressionType.NewArray: { var s = e as NewArray; var ps = new StageValue(null, MetaStage.ReadOnly, s.ArrayType.ElementType.IsReferenceType ? MetaStage.Volatile : MetaStage.Max); if (s.Size == null) { MetaStage minStage, maxStage; var initializers = ProcessValues(ref ps, out minStage, out maxStage, s.Initializers); return(new StageValue(new NewArray(s.Source, (RefArrayType)s.ReturnType, initializers), minStage, maxStage)); } else { Expression size; MetaStage minStage, maxStage; ProcessValues(ref ps, out minStage, out maxStage, s.Size, out size); return(new StageValue(new NewArray(s.Source, (RefArrayType)s.ReturnType, size), minStage, maxStage)); } } case ExpressionType.CallMethod: { var s = e as CallMethod; var ps = ProcessValue(s.Object); AdjustInstanceStageRange(ref ps, s.Method.DeclaringType, false); AdjustFunctionStageRange(ref ps, s.Method); MetaStage minStage, maxStage; var args = ProcessValues(ref ps, out minStage, out maxStage, s.Arguments); return(new StageValue(new CallMethod(s.Source, ps.Value, s.Method, args), minStage, maxStage)); } case ExpressionType.CallCast: { var s = e as CallCast; var ps = ProcessValue(s.Operand); AdjustFunctionStageRange(ref ps, s.Cast); return(new StageValue(new CallCast(s.Source, s.Cast, ps.Value), ps.MinStage, ps.MaxStage)); } case ExpressionType.CallBinOp: { var s = e as CallBinOp; var ps = StageValue.Default; AdjustFunctionStageRange(ref ps, s.Operator); Expression left, right; MetaStage minStage, maxStage; ProcessValues(ref ps, out minStage, out maxStage, s.Left, out left, s.Right, out right); return(new StageValue(new CallBinOp(s.Source, s.Operator, left, right), minStage, maxStage)); } case ExpressionType.CallUnOp: { var s = e as CallUnOp; var ps = ProcessValue(s.Operand); AdjustFunctionStageRange(ref ps, s.Operator); return(new StageValue(new CallUnOp(s.Source, s.Operator, ps.Value), ps.MinStage, ps.MaxStage)); } case ExpressionType.CastOp: { var s = e as CastOp; var ps = ProcessValue(s.Operand); if (ps.MaxStage > MetaStage.Volatile) { ps.MaxStage = MetaStage.Volatile; } return(new StageValue(new CastOp(s.Source, s.ReturnType, ps.Value), ps.MinStage, ps.MaxStage)); } case ExpressionType.StoreElement: case ExpressionType.StoreField: case ExpressionType.StoreArgument: case ExpressionType.StoreLocal: case ExpressionType.SetProperty: Log.Error(e.Source, ErrorCode.E5021, "Not allowed to use assign operators inside meta property definitions"); return(new StageValue(Expression.Invalid, MetaStage.Const)); } Log.Error(e.Source, ErrorCode.I5022, "<" + e.ExpressionType + "> is not supported by ShaderGenerator"); return(new StageValue(Expression.Invalid, MetaStage.Const)); }
Expression[] ProcessValues(ref StageValue obj, out MetaStage minStage, out MetaStage maxStage, params Expression[] args) { switch (args.Length) { case 0: minStage = obj.MinStage; maxStage = obj.MaxStage; return(new Expression[0]); case 1: { Expression arg; ProcessValues(ref obj, out minStage, out maxStage, args[0], out arg); return(new[] { arg }); } case 2: { Expression arg0, arg1; ProcessValues(ref obj, out minStage, out maxStage, args[0], out arg0, args[1], out arg1); return(new[] { arg0, arg1 }); } default: { minStage = obj.MinStage; maxStage = obj.MaxStage; var stageArgs = new StageValue[args.Length]; for (int i = 0; i < args.Length; i++) { stageArgs[i] = ProcessValue(args[i]); if (stageArgs[i].MinStage > minStage) { minStage = stageArgs[i].MinStage; } if (stageArgs[i].MaxStage < maxStage) { maxStage = stageArgs[i].MaxStage; } } if (maxStage < minStage) { maxStage = minStage; } var result = new Expression[args.Length]; for (int i = 0; i < args.Length; i++) { result[i] = ProcessStage(stageArgs[i], minStage, maxStage).Value; } obj = ProcessStage(obj, minStage, maxStage); return(result); } } }