/// <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> /// 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> /// 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(XenkoTags.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 XenkoReplaceAppend(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> /// 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> /// Organize the streams for the compute shader /// </summary> /// <param name="streamStageUsage">the StreamStageUsage of the compute stage</param> private void ComputeShaderStreamAnalysis(StreamStageUsage streamStageUsage) { if (streamStageUsage.ShaderStage == XkShaderStage.Compute) { streamStageUsage.InterStreamList.AddRange(streamStageUsage.OutStreamList); streamStageUsage.OutStreamList.Clear(); } }
/// <summary> /// Get the streams usage for this entrypoint /// </summary> /// <param name="moduleMixin">the current module mixin</param> /// <param name="entryPoint">the entrypoint method</param> /// <returns>a StreamStageUsage containing the streams usages</returns> private StreamStageUsage StreamAnalysisPerShader(ModuleMixin moduleMixin, MethodDeclaration entryPoint, XkShaderStage shaderStage) { var visitedMethods = new List<MethodDeclaration>(); var streamStageUsage = new StreamStageUsage { ShaderStage = shaderStage }; FindStreamsUsage(entryPoint, streamStageUsage.InStreamList, streamStageUsage.OutStreamList, visitedMethods); visitedMethods.Clear(); return streamStageUsage; }
/// <summary> /// Creates an intermediate structure given the stream usage /// </summary> /// <param name="streamStageUsage">the StreamStageUsage</param> /// <param name="stageName">the name of the stage</param> /// <returns>the intermediate stream structure</returns> private static StructType CreateIntermediateStructType(StreamStageUsage streamStageUsage, string stageName) { var tempList = new List<IDeclaration>(); tempList.AddRange(streamStageUsage.InStreamList); tempList.AddRange(streamStageUsage.InterStreamList); tempList.AddRange(streamStageUsage.OutStreamList); return CreateStreamStructure(tempList.Distinct().ToList(), stageName + "_STREAMS", false, false); }