internal static ShaderFunctionAndMethodDeclarationSyntax GetShaderFunction( MethodDeclarationSyntax node, Compilation compilation, bool generateOrderedFunctionList) { string functionName = node.Identifier.ToFullString(); List <ParameterDefinition> parameters = new List <ParameterDefinition>(); foreach (ParameterSyntax ps in node.ParameterList.Parameters) { parameters.Add(ParameterDefinition.GetParameterDefinition(compilation, ps)); } SemanticModel semanticModel = compilation.GetSemanticModel(node.SyntaxTree); TypeReference returnType = new TypeReference(semanticModel.GetFullTypeName(node.ReturnType), semanticModel.GetTypeInfo(node.ReturnType)); UInt3 computeGroupCounts = new UInt3(); bool isFragmentShader = false, isComputeShader = false; bool isVertexShader = GetMethodAttributes(node, "VertexShader").Any(); if (!isVertexShader) { isFragmentShader = GetMethodAttributes(node, "FragmentShader").Any(); } if (!isVertexShader && !isFragmentShader) { AttributeSyntax computeShaderAttr = GetMethodAttributes(node, "ComputeShader").FirstOrDefault(); if (computeShaderAttr != null) { isComputeShader = true; computeGroupCounts.X = GetAttributeArgumentUIntValue(computeShaderAttr, 0); computeGroupCounts.Y = GetAttributeArgumentUIntValue(computeShaderAttr, 1); computeGroupCounts.Z = GetAttributeArgumentUIntValue(computeShaderAttr, 2); } } ShaderFunctionType type = isVertexShader ? ShaderFunctionType.VertexEntryPoint : isFragmentShader ? ShaderFunctionType.FragmentEntryPoint : isComputeShader ? ShaderFunctionType.ComputeEntryPoint : ShaderFunctionType.Normal; string nestedTypePrefix = GetFullNestedTypePrefix(node, out bool nested); ShaderFunction sf = new ShaderFunction( nestedTypePrefix, functionName, returnType, parameters.ToArray(), type, computeGroupCounts); ShaderFunctionAndMethodDeclarationSyntax[] orderedFunctionList; if (type != ShaderFunctionType.Normal && generateOrderedFunctionList) { FunctionCallGraphDiscoverer fcgd = new FunctionCallGraphDiscoverer( compilation, new TypeAndMethodName { TypeName = sf.DeclaringType, MethodName = sf.Name }); fcgd.GenerateFullGraph(); orderedFunctionList = fcgd.GetOrderedCallList(); } else { orderedFunctionList = new ShaderFunctionAndMethodDeclarationSyntax[0]; } return(new ShaderFunctionAndMethodDeclarationSyntax(sf, node, orderedFunctionList)); }
private void WriteMainFunction(string setName, StringBuilder sb, ShaderFunction entryFunction) { ParameterDefinition input = entryFunction.Parameters.Length > 0 ? entryFunction.Parameters[0] : null; StructureDefinition inputType = input != null ? GetRequiredStructureType(setName, input.Type) : null; StructureDefinition outputType = entryFunction.ReturnType.Name != "System.Numerics.Vector4" && entryFunction.ReturnType.Name != "System.Void" ? GetRequiredStructureType(setName, entryFunction.ReturnType) : null; string fragCoordName = null; if (inputType != null) { // Declare "in" variables int inVarIndex = 0; fragCoordName = null; foreach (FieldDefinition field in inputType.Fields) { if (entryFunction.Type == ShaderFunctionType.FragmentEntryPoint && fragCoordName == null && field.SemanticType == SemanticType.SystemPosition) { fragCoordName = field.Name; } else { WriteInOutVariable( sb, true, entryFunction.Type == ShaderFunctionType.VertexEntryPoint, CSharpToShaderType(field.Type.Name), CorrectIdentifier(field.Name), inVarIndex); inVarIndex += 1; } } } string mappedReturnType = CSharpToShaderType(entryFunction.ReturnType.Name); // Declare "out" variables if (entryFunction.Type == ShaderFunctionType.VertexEntryPoint) { int outVarIndex = 0; foreach (FieldDefinition field in outputType.Fields) { if (field.SemanticType == SemanticType.SystemPosition) { continue; } else { WriteInOutVariable( sb, false, true, CSharpToShaderType(field.Type.Name), "out_" + CorrectIdentifier(field.Name), outVarIndex); outVarIndex += 1; } } } else { Debug.Assert(entryFunction.Type == ShaderFunctionType.FragmentEntryPoint || entryFunction.Type == ShaderFunctionType.ComputeEntryPoint); if (mappedReturnType == "vec4") { WriteInOutVariable(sb, false, false, "vec4", "_outputColor_", 0); } else if (mappedReturnType != "void") { // Composite struct -- declare an out variable for each. int colorTargetIndex = 0; foreach (FieldDefinition field in outputType.Fields) { Debug.Assert(field.SemanticType == SemanticType.ColorTarget); Debug.Assert(field.Type.Name == "System.Numerics.Vector4"); int index = colorTargetIndex++; sb.AppendLine($" layout(location = {index}) out vec4 _outputColor_{index};"); } } } sb.AppendLine(); sb.AppendLine($"void main()"); sb.AppendLine("{"); if (inputType != null) { string inTypeName = CSharpToShaderType(inputType.Name); sb.AppendLine($" {inTypeName} {CorrectIdentifier("input")};"); // Assign synthetic "in" variables (with real field name) to structure passed to actual function. int inoutIndex = 0; bool foundSystemPosition = false; foreach (FieldDefinition field in inputType.Fields) { if (entryFunction.Type == ShaderFunctionType.VertexEntryPoint) { sb.AppendLine($" {CorrectIdentifier("input")}.{CorrectIdentifier(field.Name)} = {CorrectIdentifier(field.Name)};"); } else { if (field.SemanticType == SemanticType.SystemPosition && !foundSystemPosition) { Debug.Assert(field.Name == fragCoordName); foundSystemPosition = true; sb.AppendLine($" {CorrectIdentifier("input")}.{CorrectIdentifier(field.Name)} = gl_FragCoord;"); } else { sb.AppendLine($" {CorrectIdentifier("input")}.{CorrectIdentifier(field.Name)} = fsin_{inoutIndex++};"); } } } } // Call actual function. string invocationStr = inputType != null ? $"{entryFunction.Name}({CorrectIdentifier("input")})" : $"{entryFunction.Name}()"; if (mappedReturnType != "void") { sb.AppendLine($" {mappedReturnType} {CorrectIdentifier("output")} = {invocationStr};"); } else { sb.AppendLine($" {invocationStr};"); } // Assign output fields to synthetic "out" variables with normalized "fsin_#" names. if (entryFunction.Type == ShaderFunctionType.VertexEntryPoint) { int inoutIndex = 0; FieldDefinition systemPositionField = null; foreach (FieldDefinition field in outputType.Fields) { if (systemPositionField == null && field.SemanticType == SemanticType.SystemPosition) { systemPositionField = field; } else { sb.AppendLine($" fsin_{inoutIndex++} = {CorrectIdentifier("output")}.{CorrectIdentifier(field.Name)};"); } } if (systemPositionField == null) { // TODO: Should be caught earlier. throw new ShaderGenerationException("Vertex functions must output a SystemPosition semantic."); } sb.AppendLine($" gl_Position = {CorrectIdentifier("output")}.{CorrectIdentifier(systemPositionField.Name)};"); EmitGlPositionCorrection(sb); } else if (entryFunction.Type == ShaderFunctionType.FragmentEntryPoint) { if (mappedReturnType == "vec4") { sb.AppendLine($" _outputColor_ = {CorrectIdentifier("output")};"); } else if (mappedReturnType != "void") { // Composite struct -- assign each field to output int colorTargetIndex = 0; foreach (FieldDefinition field in outputType.Fields) { Debug.Assert(field.SemanticType == SemanticType.ColorTarget); sb.AppendLine($" _outputColor_{colorTargetIndex++} = {CorrectIdentifier("output")}.{CorrectIdentifier(field.Name)};"); } } } sb.AppendLine("}"); }
protected virtual string FormatInvocationParameter(ParameterDefinition def, InvocationParameterInfo ipi) { return(CSharpToIdentifierNameCore(ipi.FullTypeName, ipi.Identifier)); }
private void WriteMainFunction(string setName, StringBuilder sb, ShaderFunction entryFunction) { ParameterDefinition input = entryFunction.Parameters[0]; StructureDefinition inputType = GetRequiredStructureType(setName, input.Type); StructureDefinition outputType = entryFunction.Type == ShaderFunctionType.VertexEntryPoint ? GetRequiredStructureType(setName, entryFunction.ReturnType) : null; // Hacky but meh // Declare "in" variables int inVarIndex = 0; string fragCoordName = null; foreach (FieldDefinition field in inputType.Fields) { if (entryFunction.Type == ShaderFunctionType.FragmentEntryPoint && fragCoordName == null && field.SemanticType == SemanticType.Position) { fragCoordName = field.Name; } else { WriteInOutVariable( sb, true, entryFunction.Type == ShaderFunctionType.VertexEntryPoint, CSharpToShaderType(field.Type.Name), CorrectIdentifier(field.Name), inVarIndex); inVarIndex += 1; } } string mappedReturnType = CSharpToShaderType(entryFunction.ReturnType.Name); // Declare "out" variables if (entryFunction.Type == ShaderFunctionType.VertexEntryPoint) { bool skippedFirstPositionSemantic = false; int outVarIndex = 0; foreach (FieldDefinition field in outputType.Fields) { if (field.SemanticType == SemanticType.Position && !skippedFirstPositionSemantic) { skippedFirstPositionSemantic = true; continue; } else { WriteInOutVariable( sb, false, true, CSharpToShaderType(field.Type.Name), "out_" + CorrectIdentifier(field.Name), outVarIndex); outVarIndex += 1; } } } else { Debug.Assert(entryFunction.Type == ShaderFunctionType.FragmentEntryPoint); if (mappedReturnType != "vec4" && mappedReturnType != "void") { throw new ShaderGenerationException("Fragment shader must return a System.Numerics.Vector4 value, or no value."); } if (mappedReturnType == "vec4") { WriteInOutVariable(sb, false, false, "vec4", "_outputColor_", 0); } } sb.AppendLine(); string inTypeName = CSharpToShaderType(inputType.Name); sb.AppendLine($"void main()"); sb.AppendLine("{"); sb.AppendLine($" {inTypeName} {CorrectIdentifier("input")};"); // Assign synthetic "in" variables (with real field name) to structure passed to actual function. int inoutIndex = 0; bool foundSystemPosition = false; foreach (FieldDefinition field in inputType.Fields) { if (entryFunction.Type == ShaderFunctionType.VertexEntryPoint) { sb.AppendLine($" {CorrectIdentifier("input")}.{CorrectIdentifier(field.Name)} = {CorrectIdentifier(field.Name)};"); } else { if (field.SemanticType == SemanticType.Position && !foundSystemPosition) { Debug.Assert(field.Name == fragCoordName); foundSystemPosition = true; sb.AppendLine($" {CorrectIdentifier("input")}.{CorrectIdentifier(field.Name)} = gl_FragCoord;"); } else { sb.AppendLine($" {CorrectIdentifier("input")}.{CorrectIdentifier(field.Name)} = fsin_{inoutIndex++};"); } } } // Call actual function. if (mappedReturnType != "void") { sb.AppendLine($" {mappedReturnType} {CorrectIdentifier("output")} = {entryFunction.Name}({CorrectIdentifier("input")});"); } else { sb.Append($" {entryFunction.Name}({CorrectIdentifier("input")});"); } // Assign output fields to synthetic "out" variables with normalized "fsin_#" names. if (entryFunction.Type == ShaderFunctionType.VertexEntryPoint) { inoutIndex = 0; FieldDefinition positionSemanticField = null; foreach (FieldDefinition field in outputType.Fields) { if (positionSemanticField == null && field.SemanticType == SemanticType.Position) { positionSemanticField = field; } else { sb.AppendLine($" fsin_{inoutIndex++} = {CorrectIdentifier("output")}.{CorrectIdentifier(field.Name)};"); } } if (positionSemanticField == null) { // TODO: Should be caught earlier. throw new ShaderGenerationException("At least one vertex output must have a position semantic."); } sb.AppendLine($" gl_Position = {CorrectIdentifier("output")}.{CorrectIdentifier(positionSemanticField.Name)};"); EmitGlPositionCorrection(sb); } else { Debug.Assert(entryFunction.Type == ShaderFunctionType.FragmentEntryPoint); if (mappedReturnType == "vec4") { sb.AppendLine($" _outputColor_ = {CorrectIdentifier("output")};"); } } sb.AppendLine("}"); }