public override void Run(MethodDefinition methodEntry) { base.Run(methodEntry); var existingTextures = new HashSet<Variable>(samplerMapping.Select(x => x.Key.Texture)); foreach (var texture in textureAccesses) { if (!existingTextures.Contains(texture)) GenerateGLSampler(null, texture); } for (int i = this.textureSamplerMethods.Count - 1; i >= 0; i--) { var textureSamplerMethodKey = this.textureSamplerMethods[i]; var entryIndex = shader.Declarations.IndexOf(textureSamplerMethodKey.Method); this.shader.Declarations.Insert(entryIndex, textureSamplerMethodKey.NewMethod); } }
protected virtual void ProcessMethodInvocation(MethodInvocationExpression invoke, MethodDefinition method) { this.VisitDynamic(method); }
public virtual void Run(MethodDefinition methodEntry) { base.Visit(methodEntry); }
protected override void ProcessMethodInvocation(MethodInvocationExpression invoke, MethodDefinition method) { // Handle the case where a parameter can be out // If this is the case, we need to check that for (int i = 0; i < invoke.Arguments.Count; i++) { var arg = invoke.Arguments[i]; var variable = this.GetUniform(arg); var parameter = method.Parameters[i]; if (variable != null && parameter.Qualifiers.Contains(Ast.Hlsl.ParameterQualifier.Out)) { bool isUniformWasAlreadyUsedAsRead = false; for (int j = 0; j < countReadBeforeInvoke; j++) { if (ReferenceEquals(uniformReadList[i], variable)) { isUniformWasAlreadyUsedAsRead = true; break; } } // If this is a out parameter, and the variable was not already used as a read, then // we can remove it from the uniform read list if (!isUniformWasAlreadyUsedAsRead) { uniformReadList.Remove(variable); if (!UniformUsedWriteFirstList.Contains(variable)) UniformUsedWriteFirstList.Add(variable); } } } this.VisitDynamic(method); }
/// <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; }
public virtual void Visit(MethodDefinition methodDefinition) { WriteLinkLine(methodDefinition); WriteMethodDeclaration(methodDefinition); OpenBrace(); foreach (var statement in methodDefinition.Body) VisitDynamic(statement); CloseBrace(); }
/// <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; }
protected void Visit(MethodDefinition method) { // Parse stream output declarations (if any) // TODO: Currently done twice, one time in ShaderMixer, one time in ShaderLinker var streamOutputAttribute = method.Attributes.OfType<AttributeDeclaration>().FirstOrDefault(x => x.Name == "StreamOutput"); if (streamOutputAttribute != null) { var rasterizedStream = streamOutputAttribute.Parameters.LastOrDefault(); // Ignore last parameter if it's not an integer (it means there is no rasterized stream info) // We should make a new StreamOutputRasterizedStream attribute instead maybe? if (rasterizedStream != null && !(rasterizedStream.Value is int)) rasterizedStream = null; int[] streamOutputStrides; // Parse declarations // Everything should be registered in GS_OUTPUT (previous pass in ShaderMixer). StreamOutputParser.Parse(effectReflection.ShaderStreamOutputDeclarations, out streamOutputStrides, streamOutputAttribute, ((StructType)FindDeclaration("GS_OUTPUT")).Fields); effectReflection.StreamOutputStrides = streamOutputStrides; effectReflection.StreamOutputRasterizedStream = rasterizedStream != null ? (int)rasterizedStream.Value : -1; } }
/// <summary> /// Modify the Hull shader constant /// </summary> /// <param name="entryPoint">the entrypoint method</param> /// <param name="inStreamStructTypeName">the input structure of the Hull shader</param> /// <param name="outStreamStructTypeName">the output structure of the Hull shader</param> private void GenerateStreamsForHullShaderConstant(MethodDefinition entryPoint, TypeName inStreamStructTypeName, TypeName outStreamStructTypeName) { if (entryPoint != null) { var constStreamStruct = CreateStreamStructure(mainModuleMixin.VirtualTable.Variables.Select(x => x.Variable).Where(x => x.Qualifiers.Contains(ParadoxStorageQualifier.PatchStream)).Distinct().ToList<IDeclaration>(), "HS_CONSTANTS"); var typeConst = new TypeName(constStreamStruct.Name); var visitedMethods = new Stack<MethodDeclaration>(); RecursiveRename(entryPoint, inStreamStructTypeName, outStreamStructTypeName, outStreamStructTypeName, typeConst, visitedMethods); // get the Constants parameter, its name and remove it var constParamName = "constants"; var constParam = entryPoint.Parameters.FirstOrDefault(x => x.Type.Name.Text == constStreamStruct.Name.Text); if (constParam != null) { constParamName = constParam.Name.Text; entryPoint.Parameters.Remove(constParam); // remove the parameter } var constDecl = new DeclarationStatement( new Variable(typeConst, constParamName) { InitialValue = new CastExpression { From = new LiteralExpression(0), Target = new TypeName(constStreamStruct.Name) } }); entryPoint.Body.Insert(0, constDecl); // insert structure instance declaration entryPoint.Body.Add(new ReturnStatement(new VariableReferenceExpression(constParamName))); // add a return statement entryPoint.ReturnType = typeConst; // change the return type shader.Members.Insert(0, constStreamStruct); } }
/// <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 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> /// Replace the append methods /// </summary> /// <param name="entryPoint">the entrypoint method</param> /// <param name="replacor">the visitor</param> private void ReplaceAppendMethod(MethodDefinition entryPoint, ParadoxReplaceAppend replacor) { replacor.Run(entryPoint); List<StreamUsageInfo> nextMethods; if (streamsUsages.TryGetValue(entryPoint, out nextMethods)) nextMethods.Where(x => x.CallType == StreamCallType.Method).Select(x => x.MethodDeclaration as MethodDefinition).Where(x => x != null).ToList().ForEach(x => ReplaceAppendMethod(x, replacor)); }
/// <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; }
protected void Visit(MethodDefinition methodDefinition) { currentStreamUsageList = new List<StreamUsageInfo>(); alreadyAddedMethodsList = new List<MethodDeclaration>(); Visit((Node)methodDefinition); if (currentStreamUsageList.Count > 0) StreamsUsageByMethodDefinition.Add(methodDefinition, currentStreamUsageList); }
/// <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> /// Analyse the method definition and store it in the correct lists (based on storage and stream usage) /// </summary> /// <param name="methodDefinition">the MethodDefinition</param> public override void Visit(MethodDefinition methodDefinition) { currentStreamUsageList = new List<StreamUsageInfo>(); alreadyAddedMethodsList = new List<MethodDeclaration>(); base.Visit(methodDefinition); if (currentStreamUsageList.Count > 0) StreamsUsageByMethodDefinition.Add(methodDefinition, currentStreamUsageList); }
protected virtual MethodDefinition Visit(MethodDefinition methodDefinition) { Visit((Node)methodDefinition); // Check that this method definition doesn't have a method declaration before foreach (var declaration in FindDeclarations(methodDefinition.Name)) { var methodDeclaration = declaration as MethodDeclaration; if (methodDeclaration != null && !ReferenceEquals(declaration, methodDefinition)) { if (methodDeclaration.IsSameSignature(methodDefinition)) { methodDefinition.Declaration = methodDeclaration; // Remove the definition if the declaration is tagged as builtin special (user defined) if (methodDeclaration.GetTag(TagBuiltinUserDefined) != null) return null; break; } } } return methodDefinition; }
protected override void ProcessMethodInvocation(MethodInvocationExpression invoke, MethodDefinition method) { var textureParameters = new List<Parameter>(); var parameterValues = new List<Expression>(); var parameterGlobalValues = new List<Variable>(); var samplerTypes = new List<int>(); for (int i = 0; i < method.Parameters.Count; i++) { var parameter = method.Parameters[i]; if (parameter.Type is TextureType || parameter.Type is StateType) { textureParameters.Add(parameter); // Find global variable var parameterValue = this.FindGlobalVariable(invoke.Arguments[i]); // Set the tag ScopeValue for the current parameter parameter.SetTag(ScopeValueKey, parameterValue); // Add only new variable if (!parameterGlobalValues.Contains(parameterValue)) parameterGlobalValues.Add(parameterValue); } else if ( i < invoke.Arguments.Count) { parameterValues.Add(invoke.Arguments[i]); if (parameter.Type is SamplerType) { samplerTypes.Add(i); } } } // We have texture/sampler parameters. We need to generate a new specialized method if (textureParameters.Count > 0) { // Order parameter values by name parameterGlobalValues.Sort((left, right) => left.Name.Text.CompareTo(right.Name.Text)); var methodKey = new TextureSamplerMethodKey(method); int indexOf = textureSamplerMethods.IndexOf(methodKey); if (indexOf < 0) { methodKey.Initialize(cloneContext); textureSamplerMethods.Add(methodKey); } else { // If a key is found again, add it as it was reused in order to keep usage in order methodKey = textureSamplerMethods[indexOf]; textureSamplerMethods.RemoveAt(indexOf); textureSamplerMethods.Add(methodKey); } methodKey.Invokers.Add(invoke); var newTarget = new VariableReferenceExpression(methodKey.NewMethod.Name) { TypeInference = { Declaration = methodKey.NewMethod, TargetType = invoke.TypeInference.TargetType } }; invoke.Target = newTarget; invoke.Arguments = parameterValues; invoke.TypeInference.Declaration = methodKey.NewMethod; invoke.TypeInference.TargetType = invoke.TypeInference.TargetType; this.VisitDynamic(methodKey.NewMethod); } else { // Visit the method callstack this.VisitDynamic(method); // There is an anonymous sampler type // We need to resolve its types after the method definition was processed if (samplerTypes.Count > 0) { foreach (var samplerTypeIndex in samplerTypes) { var samplerRef = invoke.Arguments[samplerTypeIndex] as VariableReferenceExpression; if (samplerRef != null) { var samplerDecl = samplerRef.TypeInference.Declaration as Variable; ChangeVariableType(samplerDecl, method.Parameters[samplerTypeIndex].Type); } } } } // Remove temporary parameters if (textureParameters.Count > 0) { foreach (var textureParameter in textureParameters) { textureParameter.RemoveTag(ScopeValueKey); } } }
public override void Visit(MethodDefinition methodDefinition) { base.Visit(methodDefinition); // If a method definition has a method declaration, we must link them together if (!ReferenceEquals(methodDefinition.Declaration, methodDefinition)) { AddReference(methodDefinition.Declaration, methodDefinition); } }
public TextureSamplerMethodKey(MethodDefinition method) { Invokers = new List<MethodInvocationExpression>(); this.Method = method; Variables = new List<Variable>(); foreach (var parameter in Method.Parameters) { var variableValue = (Variable)parameter.GetTag(ScopeValueKey); if (variableValue != null) { Variables.Add(variableValue); } } }
public void Visit(MethodDefinition methodDefinition) { Visit((Node)methodDefinition); // If a method definition has a method declaration, we must link them together if (!ReferenceEquals(methodDefinition.Declaration, methodDefinition)) { AddReference(methodDefinition.Declaration, methodDefinition); } }
/// <summary> /// Analyse the method definition and store it in the correct lists (based on storage and stream usage) /// </summary> /// <param name="methodDefinition">the MethodDefinition</param> /// <returns>the input method definition</returns> public override Node Visit(MethodDefinition methodDefinition) { currentVisitedMethod = methodDefinition; if (methodDefinition.Qualifiers.Contains(XenkoStorageQualifier.Abstract)) Error(XenkoMessageCode.ErrorUnnecessaryAbstract, methodDefinition.Span, methodDefinition, analyzedModuleMixin.MixinName); var ret = base.Visit(methodDefinition); PostMethodDeclarationVisit(methodDefinition); return ret; }
public virtual void Run(MethodDefinition methodEntry) { this.Visit((Node)methodEntry); }