/// <inheritdoc/> public bool Equals(StructType other) { return base.Equals(other); }
private void Visit(StructType structType) { Visit((Node)structType); if (structType.ContainsTag(ParadoxTags.ShaderScope)) parsingInfo.StructureDefinitions.Add(structType); }
/// <summary> /// Creates assignement statements with its default value /// </summary> /// <param name="streamStruct">the stream structure</param> /// <param name="streamName">the name of the stream</param> /// <param name="inputStruct">the input structure</param> /// <param name="initialValue">the initial value</param> /// <param name="scopeStack">???</param> /// <returns>A collection of statements</returns> private static IEnumerable<Statement> AssignStreamFromInput(StructType streamStruct, string streamName, StructType inputStruct, Expression initialValue, bool basicTransformation) { foreach (var currentField in inputStruct.Fields) { // Ignore fields that don't exist in Streams. // It could happen if HSConstantMain references a stream (gets added to HS_OUTPUT), // and in HSMain CreateStreamFromInput() is called (this stream doesn't exist in DS_STREAMS). if (streamStruct.Fields.All(x => x.Name != currentField.Name)) continue; // If we have a scope stack (advanced analysis), then convert expression by appending // field to each reference to a variable of inputStruct type // i.e. "output = input1 * 3 + input2 * 5" will become "output.A = input1.A * 3 + input2.A * 5" // Otherwise consider it is as a simple a variable reference and directly append field. if (basicTransformation) { yield return new ExpressionStatement( new AssignmentExpression( AssignmentOperator.Default, new MemberReferenceExpression(new VariableReferenceExpression(streamName), currentField.Name), new MemberReferenceExpression(initialValue, currentField.Name))); } else { //yield return AssignStreamFieldFromInput(streamName, inputStruct, initialValue, scopeStack, currentField); foreach (var field in streamStruct.Fields.Where(x => x.Name == currentField.Name)) // TODO: where might be useless { if (field.Type is ArrayType) { //create a for loop var iteratorName = field.Name.Text + "_Iter"; var iterator = new Variable(ScalarType.Int, iteratorName, new LiteralExpression(0)); var start = new DeclarationStatement(iterator); var condition = new BinaryExpression(BinaryOperator.Less, new VariableReferenceExpression(iterator), (field.Type as ArrayType).Dimensions[0]); var next = new UnaryExpression(UnaryOperator.PreIncrement, new VariableReferenceExpression(iterator)); var forLoop = new ForStatement(start, condition, next); var fieldAssigner = new StreamFieldVisitor(field, new VariableReferenceExpression(iterator)); var clonedExpression = fieldAssigner.Run(ParadoxAssignmentCloner.Run(initialValue)); forLoop.Body = new ExpressionStatement( new AssignmentExpression( AssignmentOperator.Default, new IndexerExpression(new MemberReferenceExpression(new VariableReferenceExpression(streamName), currentField.Name), new VariableReferenceExpression(iterator)), clonedExpression)); yield return forLoop; } else { var fieldAssigner = new StreamFieldVisitor(field); //var clonedExpression = fieldAssigner.Run(initialValue.DeepClone()); var clonedExpression = fieldAssigner.Run(ParadoxAssignmentCloner.Run(initialValue)); yield return new ExpressionStatement( new AssignmentExpression( AssignmentOperator.Default, new MemberReferenceExpression(new VariableReferenceExpression(streamName), currentField.Name), clonedExpression)); } } } } }
/// <summary> /// Finds the member type reference. /// </summary> /// <param name="structType">Type of the struct.</param> /// <param name="memberReference">The member reference.</param> protected virtual void FindMemberTypeReference(StructType structType, MemberReferenceExpression memberReference) { foreach (var field in structType.Fields) { foreach (var variableDeclarator in field.Instances()) { if (variableDeclarator.Name == memberReference.Member) { memberReference.TypeInference.Declaration = variableDeclarator; memberReference.TypeInference.TargetType = variableDeclarator.Type.ResolveType(); return; } } } }
/// <summary> /// Checks if a function needs to have a stream strucutre added in its declaration /// </summary> /// <param name="methodDefinition">the method definition</param> /// <param name="inputStream">The stage input structure stream.</param> /// <param name="intermediateStream">the stream structure</param> /// <param name="outputStream">The stage output stream structure.</param> /// <param name="visitedMethods">the list of already visited methods</param> /// <param name="methodsWithStreams">The list of methods that have a streams argument.</param> /// <returns>true if needed, false otherwise</returns> private bool PropagateStreamsParameter(MethodDefinition methodDefinition, StructType inputStream, StructType intermediateStream, StructType outputStream, HashSet<MethodDeclaration> visitedMethods, List<MethodDeclaration> methodsWithStreams) { var needStream = false; if (methodDefinition != null) { if (visitedMethods.Contains(methodDefinition)) return methodDefinition.Parameters.Count > 0 && methodDefinition.Parameters[0].Type == intermediateStream; List<StreamUsageInfo> streamUsageInfos; if (streamsUsages.TryGetValue(methodDefinition, out streamUsageInfos)) { needStream = streamUsageInfos.Any(x => x.CallType == StreamCallType.Member || x.CallType == StreamCallType.Direct); visitedMethods.Add(methodDefinition); List<MethodDeclaration> calls; if (TryGetMethodCalls(methodDefinition, out calls)) needStream = calls.Aggregate(needStream, (res, calledmethod) => res | PropagateStreamsParameter(calledmethod as MethodDefinition, inputStream, intermediateStream, outputStream, visitedMethods, methodsWithStreams)); if (needStream && !entryPointMethods.Contains(methodDefinition)) { var param = new Parameter(new TypeName(intermediateStream.Name), "streams"); foreach (var methodRef in mainModuleMixin.ClassReferences.MethodsReferences[methodDefinition]) { var vre = new VariableReferenceExpression(param.Name) { TypeInference = { Declaration = param, TargetType = param.Type } }; methodRef.Arguments.Insert(0, vre); } param.Qualifiers |= ParameterQualifier.InOut; methodDefinition.Parameters.Insert(0, param); // If any parameters in the method are streams, then replace by using the intermediate stream foreach (var parameter in methodDefinition.Parameters) { if (parameter.Type == StreamsType.Streams) { parameter.Type = new TypeName(intermediateStream.Name); } } methodsWithStreams.Add(methodDefinition); } } TransformStreamsAssignments(methodDefinition, inputStream, intermediateStream, outputStream); } return needStream; }
/// <summary> /// Transform stream assignments with correct input/ouput structures /// </summary> /// <param name="methodDefinition">the current method</param> /// <param name="inputStreamStruct">the input structure of the stage</param> /// <param name="intermediateStreamStruct">the intermediate structure of the stage</param> /// <param name="outputStreamStruct">the output structure of the stage</param> private void TransformStreamsAssignments(MethodDefinition methodDefinition, StructType inputStreamStruct, StructType intermediateStreamStruct, StructType outputStreamStruct) { var statementLists = new List<StatementList>(); SearchVisitor.Run( methodDefinition, node => { if (node is StatementList) { statementLists.Add((StatementList)node); } return node; }); // replace stream assignement with field values assignements foreach (var assignmentKeyBlock in streamAnalyzer.AssignationsToStream) { var assignment = assignmentKeyBlock.Key; var parent = assignmentKeyBlock.Value; if (!statementLists.Contains(parent)) { continue; } var index = SearchExpressionStatement(parent, assignment); // TODO: check that it is "output = streams" var statementList = CreateOutputFromStream(outputStreamStruct, (assignment.Target as VariableReferenceExpression).Name.Text, intermediateStreamStruct, "streams").ToList(); statementList.RemoveAt(0); // do not keep the variable declaration methodDefinition.Body.RemoveAt(index); methodDefinition.Body.InsertRange(index, statementList); } // replace stream assignement with field values assignements foreach (var assignmentKeyBlock in streamAnalyzer.StreamAssignations) { var assignment = assignmentKeyBlock.Key; var parent = assignmentKeyBlock.Value; if (!statementLists.Contains(parent)) { continue; } var index = SearchExpressionStatement(parent, assignment); var statementList = CreateStreamFromInput(intermediateStreamStruct, "streams", inputStreamStruct, assignment.Value, false).ToList(); statementList.RemoveAt(0); // do not keep the variable declaration parent.RemoveAt(index); parent.InsertRange(index, statementList); } foreach (var variableAndParent in streamAnalyzer.VariableStreamsAssignment) { var variable = variableAndParent.Key; var parent = variableAndParent.Value; if (!statementLists.Contains(parent)) { continue; } variable.Type = new TypeName(intermediateStreamStruct.Name); } }
/// <summary> /// Generates a stream structure and add them to the Ast - for the hull shader and hull shader constant /// </summary> /// <param name="entryPoint">the entrypoint function</param> /// <param name="entryPointHSConstant">entrypoint for the hull shader constant</param> /// <param name="streamStageUsage">the stream usage in this stage</param> /// <param name="stageName">the name of the stage</param> /// <param name="prevOuputStructure">the output structutre from the previous stage</param> /// <returns>the new output structure</returns> private StructType GenerateStreamsForHullShader(MethodDefinition entryPoint, MethodDefinition entryPointHSConstant, StreamStageUsage streamStageUsage, string stageName, StructType prevOuputStructure) { if (entryPoint != null) { // same behavior as geometry shader var outStreamStruct = GenerateStreamsWithSpecialDataInput(entryPoint, streamStageUsage, stageName, prevOuputStructure); var inStreamStruct = prevOuputStructure ?? shader.Members.OfType<StructType>().FirstOrDefault(x => x.Name.Text == stageName + "_INPUT"); var intermediateStreamStruct = shader.Members.OfType<StructType>().FirstOrDefault(x => x.Name.Text == stageName + "_STREAMS"); if (inStreamStruct == null) throw new Exception("inStreamStruct cannot be null"); var inStructType = new TypeName(inStreamStruct.Name); var outStructType = new TypeName(outStreamStruct.Name); // get the Output parameter, its name and remove it var outputName = "output"; var outputParam = entryPoint.Parameters.FirstOrDefault(x => x.Type.Name.Text == outStreamStruct.Name.Text); if (outputParam != null) { outputName = outputParam.Name.Text; // get the name of the parameter entryPoint.Parameters.Remove(outputParam); // remove the parameter } entryPoint.Body.Add(new ReturnStatement { Value = new VariableReferenceExpression(outputName) }); entryPoint.Body.Insert(0, CreateStructInit(outStreamStruct, outputName)); entryPoint.ReturnType = outStructType; if (entryPointHSConstant != null) GenerateStreamsForHullShaderConstant(entryPointHSConstant, inStructType, outStructType); return outStreamStruct; } return prevOuputStructure; }
/// <summary> /// Creates a stream structure and assign its default values /// </summary> /// <param name="streamStruct">the structure</param> /// <param name="streamName">the name of the stream</param> /// <param name="inputStruct">the inputStructure</param> /// <param name="initialValue">the initial value of the struture</param> /// <param name="scopeStack">???</param> /// <returns>a collection of statements to insert in the body of a method</returns> private static IEnumerable<Statement> CreateStreamFromInput(StructType streamStruct, string streamName, StructType inputStruct, Expression initialValue, bool basicTransformation = true) { yield return CreateStructInit(streamStruct, streamName); foreach (var statement in AssignStreamFromInput(streamStruct, streamName, inputStruct, initialValue, basicTransformation)) { yield return statement; } }
/// <summary> /// Generates a stream structure and add them to the Ast /// </summary> /// <param name="entryPoint">the entrypoint function</param> /// <param name="streamStageUsage">the stream usage in this stage</param> /// <param name="stageName">the name of the stage</param> /// <param name="prevOuputStructure">the output structutre from the previous stage</param> /// <returns>the new output structure</returns> private StructType GenerateStreams(MethodDefinition entryPoint, StreamStageUsage streamStageUsage, string stageName, StructType prevOuputStructure, bool autoGenSem = true) { if (entryPoint != null) { // create the stream structures var inStreamStruct = prevOuputStructure ?? CreateStreamStructure(streamStageUsage.InStreamList, stageName + "_INPUT"); var outStreamStruct = CreateStreamStructure(streamStageUsage.OutStreamList, stageName + "_OUTPUT", true, autoGenSem); var intermediateStreamStruct = CreateIntermediateStructType(streamStageUsage, stageName); // modify the entrypoint if (inStreamStruct.Fields.Count != 0) { entryPoint.Parameters.Add(new Parameter(new TypeName(inStreamStruct.Name), "__input__")); entryPoint.Parameters[0].Qualifiers.Values.Remove(ParameterQualifier.InOut); } // add the declaration statements to the entrypoint and fill with the values entryPoint.Body.InsertRange(0, CreateStreamFromInput(intermediateStreamStruct, "streams", inStreamStruct, new VariableReferenceExpression("__input__"))); if (outStreamStruct.Fields.Count != 0) { entryPoint.Body.AddRange(CreateOutputFromStream(outStreamStruct, "__output__", intermediateStreamStruct, "streams")); entryPoint.Body.Add(new ReturnStatement { Value = new VariableReferenceExpression("__output__") }); entryPoint.ReturnType = new TypeName(outStreamStruct.Name); } // explore all the called functions var visitedMethods = new HashSet<MethodDeclaration>(); var methodsWithStreams = new List<MethodDeclaration>(); PropagateStreamsParameter(entryPoint, inStreamStruct, intermediateStreamStruct, outStreamStruct, visitedMethods, methodsWithStreams); CheckCrossStageMethodCall(streamStageUsage.ShaderStage, methodsWithStreams); if (prevOuputStructure == null) shader.Members.Insert(0, inStreamStruct); if (outStreamStruct.Fields.Count != 0) shader.Members.Insert(0, outStreamStruct); shader.Members.Insert(0, intermediateStreamStruct); return outStreamStruct; } return prevOuputStructure; }
/// <summary> /// Generates a stream structure and add them to the Ast - for the geometry shader /// </summary> /// <param name="entryPoint">the entrypoint function</param> /// <param name="streamStageUsage">the stream usage in this stage</param> /// <param name="stageName">the name of the stage</param> /// <param name="prevOuputStructure">the output structutre from the previous stage</param> /// <returns>the new output structure</returns> private StructType GenerateStreamsWithSpecialDataInput(MethodDefinition entryPoint, StreamStageUsage streamStageUsage, string stageName, StructType prevOuputStructure) { if (entryPoint != null) { var inStreamStruct = prevOuputStructure ?? CreateStreamStructure(streamStageUsage.InStreamList, stageName + "_INPUT"); var outStreamStruct = CreateStreamStructure(streamStageUsage.OutStreamList, stageName + "_OUTPUT"); var mixin = entryPoint.GetTag(ParadoxTags.ShaderScope) as ModuleMixin; var intermediateStreamStruct = CreateIntermediateStructType(streamStageUsage, stageName); // put the streams declaration at the beginning of the method body var streamsDeclaration = new DeclarationStatement(new Variable(new TypeName(intermediateStreamStruct.Name), "streams") { InitialValue = new CastExpression { From = new LiteralExpression(0), Target = new TypeName(intermediateStreamStruct.Name) } }); entryPoint.Body.Insert(0, streamsDeclaration); // add the declaration statements to the entrypoint and fill with the values var outputStatements = CreateOutputFromStream(outStreamStruct, "output", intermediateStreamStruct, "streams").ToList(); var outputVre = new VariableReferenceExpression(((outputStatements.First() as DeclarationStatement).Content as Variable).Name); var replacor = new ParadoxReplaceAppend(streamAnalyzer.AppendMethodCalls, outputStatements, outputVre); ReplaceAppendMethod(entryPoint, replacor); var visitedMethods = new Stack<MethodDeclaration>(); var inStructType = new TypeName(inStreamStruct.Name); var outStructType = new TypeName(outStreamStruct.Name); RecursiveRename(entryPoint, inStructType, null, outStructType, null, visitedMethods); // explore all the called functions var streamsVisitedMethods = new HashSet<MethodDeclaration>(); var methodsWithStreams = new List<MethodDeclaration>(); PropagateStreamsParameter(entryPoint, inStreamStruct, intermediateStreamStruct, outStreamStruct, streamsVisitedMethods, methodsWithStreams); CheckCrossStageMethodCall(streamStageUsage.ShaderStage, methodsWithStreams); if (prevOuputStructure == null) shader.Members.Insert(0, inStreamStruct); shader.Members.Insert(0, outStreamStruct); shader.Members.Insert(0, intermediateStreamStruct); return outStreamStruct; } return prevOuputStructure; }
/// <summary> /// Creates an declaration for this structure /// </summary> /// <param name="structType">the structure</param> /// <param name="structVarName">the name of the variable</param> /// <returns>the declaration statement</returns> private static DeclarationStatement CreateStructInit(StructType structType, string structVarName) { return new DeclarationStatement( new Variable(new TypeName(structType.Name), structVarName) { InitialValue = new CastExpression { From = new LiteralExpression(0), Target = new TypeName(structType.Name) } }); }
/// <summary> /// Generate a stream structure /// </summary> /// <param name="streamsDeclarationList">the list of the declarations</param> /// <param name="structName">the name of the structure</param> /// <returns>the structure</returns> private static StructType CreateStreamStructure(List<IDeclaration> streamsDeclarationList, string structName, bool useSem = true, bool addAutoSem = true) { var tempStruct = new StructType { Name = new Identifier(structName) }; foreach (var streamDecl in streamsDeclarationList) { var streamVar = streamDecl as Variable; if (streamVar != null) { var variable = new Variable(streamVar.Type, streamVar.Name) { Span = streamVar.Span }; if (useSem) foreach (var qualifier in streamVar.Qualifiers.OfType<Semantic>()) variable.Qualifiers |= qualifier; if (useSem && addAutoSem) { var semantic = variable.Qualifiers.Values.OfType<Semantic>().FirstOrDefault(); if (semantic == null) variable.Qualifiers |= new Semantic(variable.Name.Text.ToUpper() + "_SEM"); } tempStruct.Fields.Add(variable); } } return tempStruct; }
/// <summary> /// Creates an output stream structure and assign its default values /// </summary> /// <param name="outputStruct">the structuer</param> /// <param name="outputName">the name of the structure</param> /// <param name="streamStruct">>the initial value of the struture</param> /// <param name="streamName">the name of the stream</param> /// <returns>a collection of statements to insert in the body of a method</returns> private static IEnumerable<Statement> CreateOutputFromStream(StructType outputStruct, string outputName, StructType streamStruct, string streamName) { yield return CreateStructInit(outputStruct, outputName); foreach (var statement in AssignOutputFromStream(outputStruct, outputName, streamStruct, streamName)) { yield return statement; } }
public virtual void Visit(StructType structType) { WriteLinkLine(structType); // Pre Attributes Write(structType.Attributes, true); WriteLinkLine(structType); Write("struct"); if (structType.Name != null) { Write(" "); Write(structType.Name); WriteSpace(); } // Post Attributes Write(structType.Attributes, false); OpenBrace(); foreach (var variableDeclaration in structType.Fields) VisitDynamic(variableDeclaration); CloseBrace(false).Write(";").WriteLine(); }
/// <summary> /// Generates a stream structure and add them to the Ast - for the domain shader /// </summary> /// <param name="entryPoint">the entrypoint function</param> /// <param name="streamStageUsage">the stream usage in this stage</param> /// <param name="stageName">the name of the stage</param> /// <param name="prevOuputStructure">the output structutre from the previous stage</param> /// <returns>the new output structure</returns> private StructType GenerateStreamsForDomainShader(MethodDefinition entryPoint, StreamStageUsage streamStageUsage, string stageName, StructType prevOuputStructure) { if (entryPoint != null) { var outStreamStruct = GenerateStreamsForHullShader(entryPoint, null, streamStageUsage, stageName, prevOuputStructure); var visitedMethods = new Stack<MethodDeclaration>(); RecursiveRename(entryPoint, null, null, null, new TypeName("HS_CONSTANTS"), visitedMethods); return outStreamStruct; } return prevOuputStructure; }
/// <summary> /// Visit a structure and store its definition /// </summary> /// <param name="structType">the structure definition</param> public override Node Visit(StructType structType) { if (structType.ContainsTag(XenkoTags.ShaderScope)) parsingInfo.StructureDefinitions.Add(structType); return base.Visit(structType); }
/// <summary> /// Creates assignement statements with its default value /// </summary> /// <param name="outputStruct">the output structure</param> /// <param name="outputName">the name of the output stream</param> /// <param name="streamStruct">the stream structure</param> /// <param name="streamName">the name of the stream</param> /// <returns>a collection of statements</returns> private static IEnumerable<Statement> AssignOutputFromStream(StructType outputStruct, string outputName, StructType streamStruct, string streamName) { foreach (var currentField in outputStruct.Fields) { yield return new ExpressionStatement( new AssignmentExpression( AssignmentOperator.Default, new MemberReferenceExpression(new VariableReferenceExpression(outputName), currentField.Name), new MemberReferenceExpression(new VariableReferenceExpression(streamName), currentField.Name))); } }