Пример #1
0
        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("}");
        }
Пример #3
0
 protected virtual string FormatInvocationParameter(ParameterDefinition def, InvocationParameterInfo ipi)
 {
     return(CSharpToIdentifierNameCore(ipi.FullTypeName, ipi.Identifier));
 }
Пример #4
0
        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("}");
        }