Exemplo n.º 1
0
        private static void Generate(CodeGenContext context, StructuredProgramInfo info, int funcIndex)
        {
            var function = info.Functions[funcIndex];

            (_, var spvFunc) = context.GetFunction(funcIndex);

            context.AddFunction(spvFunc);
            context.StartFunction();

            Declarations.DeclareParameters(context, function);

            context.EnterBlock(function.MainBlock);

            Declarations.DeclareLocals(context, function);
            Declarations.DeclareLocalForArgs(context, info.Functions);

            Generate(context, function.MainBlock);

            // Functions must always end with a return.
            if (!(function.MainBlock.Last is AstOperation operation) ||
                (operation.Inst != Instruction.Return && operation.Inst != Instruction.Discard))
            {
                context.Return();
            }

            context.FunctionEnd();

            if (funcIndex == 0)
            {
                context.AddEntryPoint(context.Config.Stage.Convert(), spvFunc, "main", context.GetMainInterface());

                if (context.Config.Stage == ShaderStage.TessellationControl)
                {
                    context.AddExecutionMode(spvFunc, ExecutionMode.OutputVertices, (SpvLiteralInteger)context.Config.ThreadsPerInputPrimitive);
                }
                else if (context.Config.Stage == ShaderStage.TessellationEvaluation)
                {
                    switch (context.Config.GpuAccessor.QueryTessPatchType())
                    {
                    case TessPatchType.Isolines:
                        context.AddExecutionMode(spvFunc, ExecutionMode.Isolines);
                        break;

                    case TessPatchType.Triangles:
                        context.AddExecutionMode(spvFunc, ExecutionMode.Triangles);
                        break;

                    case TessPatchType.Quads:
                        context.AddExecutionMode(spvFunc, ExecutionMode.Quads);
                        break;
                    }

                    switch (context.Config.GpuAccessor.QueryTessSpacing())
                    {
                    case TessSpacing.EqualSpacing:
                        context.AddExecutionMode(spvFunc, ExecutionMode.SpacingEqual);
                        break;

                    case TessSpacing.FractionalEventSpacing:
                        context.AddExecutionMode(spvFunc, ExecutionMode.SpacingFractionalEven);
                        break;

                    case TessSpacing.FractionalOddSpacing:
                        context.AddExecutionMode(spvFunc, ExecutionMode.SpacingFractionalOdd);
                        break;
                    }

                    if (context.Config.GpuAccessor.QueryTessCw())
                    {
                        context.AddExecutionMode(spvFunc, ExecutionMode.VertexOrderCw);
                    }
                    else
                    {
                        context.AddExecutionMode(spvFunc, ExecutionMode.VertexOrderCcw);
                    }
                }
                else if (context.Config.Stage == ShaderStage.Geometry)
                {
                    InputTopology inputTopology = context.Config.GpuAccessor.QueryPrimitiveTopology();

                    context.AddExecutionMode(spvFunc, inputTopology switch
                    {
                        InputTopology.Points => ExecutionMode.InputPoints,
                        InputTopology.Lines => ExecutionMode.InputLines,
                        InputTopology.LinesAdjacency => ExecutionMode.InputLinesAdjacency,
                        InputTopology.Triangles => ExecutionMode.Triangles,
                        InputTopology.TrianglesAdjacency => ExecutionMode.InputTrianglesAdjacency,
                        _ => throw new InvalidOperationException($"Invalid input topology \"{inputTopology}\".")
                    });