Ejemplo n.º 1
0
 public static void DeclareParameters(CodeGenContext context, StructuredFunction function)
 {
     DeclareParameters(context, function.InArguments, 0);
     DeclareParameters(context, function.OutArguments, function.InArguments.Length);
 }
Ejemplo n.º 2
0
 private static void DeclareSharedMemory(CodeGenContext context, int size)
 {
     context.SharedMemory = DeclareMemory(context, StorageClass.Workgroup, size);
 }
Ejemplo n.º 3
0
 private static void DeclareLocalMemory(CodeGenContext context, int size)
 {
     context.LocalMemory = DeclareMemory(context, StorageClass.Private, size);
 }
Ejemplo n.º 4
0
        public static byte[] Generate(StructuredProgramInfo info, ShaderConfig config)
        {
            SpvInstructionPool    instPool;
            SpvLiteralIntegerPool integerPool;

            lock (PoolLock)
            {
                instPool    = InstructionPool.Allocate();
                integerPool = IntegerPool.Allocate();
            }

            CodeGenContext context = new CodeGenContext(info, config, instPool, integerPool);

            context.AddCapability(Capability.GroupNonUniformBallot);
            context.AddCapability(Capability.ImageBuffer);
            context.AddCapability(Capability.ImageGatherExtended);
            context.AddCapability(Capability.ImageQuery);
            context.AddCapability(Capability.SampledBuffer);
            context.AddCapability(Capability.SubgroupBallotKHR);
            context.AddCapability(Capability.SubgroupVoteKHR);

            if (config.TransformFeedbackEnabled && config.LastInVertexPipeline)
            {
                context.AddCapability(Capability.TransformFeedback);
            }

            if (config.Stage == ShaderStage.Fragment && context.Config.GpuAccessor.QueryHostSupportsFragmentShaderInterlock())
            {
                context.AddCapability(Capability.FragmentShaderPixelInterlockEXT);
                context.AddExtension("SPV_EXT_fragment_shader_interlock");
            }
            else if (config.Stage == ShaderStage.Geometry)
            {
                context.AddCapability(Capability.Geometry);

                if (config.GpPassthrough && context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough())
                {
                    context.AddExtension("SPV_NV_geometry_shader_passthrough");
                    context.AddCapability(Capability.GeometryShaderPassthroughNV);
                }
            }
            else if (config.Stage == ShaderStage.TessellationControl || config.Stage == ShaderStage.TessellationEvaluation)
            {
                context.AddCapability(Capability.Tessellation);
            }

            context.AddExtension("SPV_KHR_shader_ballot");
            context.AddExtension("SPV_KHR_subgroup_vote");

            Declarations.DeclareAll(context, info);

            if ((info.HelperFunctionsMask & NeedsInvocationIdMask) != 0)
            {
                Declarations.DeclareInvocationId(context);
            }

            for (int funcIndex = 0; funcIndex < info.Functions.Count; funcIndex++)
            {
                var function = info.Functions[funcIndex];
                var retType  = context.GetType(function.ReturnType.Convert());

                var funcArgs = new SpvInstruction[function.InArguments.Length + function.OutArguments.Length];

                for (int argIndex = 0; argIndex < funcArgs.Length; argIndex++)
                {
                    var argType        = context.GetType(function.GetArgumentType(argIndex).Convert());
                    var argPointerType = context.TypePointer(StorageClass.Function, argType);
                    funcArgs[argIndex] = argPointerType;
                }

                var funcType = context.TypeFunction(retType, false, funcArgs);
                var spvFunc  = context.Function(retType, FunctionControlMask.MaskNone, funcType);

                context.DeclareFunction(funcIndex, function, spvFunc);
            }

            for (int funcIndex = 0; funcIndex < info.Functions.Count; funcIndex++)
            {
                Generate(context, info, funcIndex);
            }

            byte[] result = context.Generate();

            lock (PoolLock)
            {
                InstructionPool.Release(instPool);
                IntegerPool.Release(integerPool);
            }

            return(result);
        }
Ejemplo n.º 5
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}\".")
                    });
Ejemplo n.º 6
0
        private static SpvInstruction ApplyScaling2D(CodeGenContext context, SpvInstruction vector, int index)
        {
            var pointerType = context.TypePointer(StorageClass.Uniform, context.TypeFP32());
            var fieldIndex  = context.Constant(context.TypeU32(), 4);
            var scaleIndex  = context.Constant(context.TypeU32(), index);

            if (context.Config.Stage == ShaderStage.Vertex)
            {
                var scaleCountPointerType = context.TypePointer(StorageClass.Uniform, context.TypeS32());
                var scaleCountElemPointer = context.AccessChain(scaleCountPointerType, context.SupportBuffer, context.Constant(context.TypeU32(), 3));
                var scaleCount            = context.Load(context.TypeS32(), scaleCountElemPointer);

                scaleIndex = context.IAdd(context.TypeU32(), scaleIndex, scaleCount);
            }

            scaleIndex = context.IAdd(context.TypeU32(), scaleIndex, context.Constant(context.TypeU32(), 1));

            var scaleElemPointer = context.AccessChain(pointerType, context.SupportBuffer, fieldIndex, scaleIndex);
            var scale            = context.Load(context.TypeFP32(), scaleElemPointer);

            var ivector2Type = context.TypeVector(context.TypeS32(), 2);
            var localVector  = context.CoordTemp;

            var passthrough = context.FOrdEqual(context.TypeBool(), scale, context.Constant(context.TypeFP32(), 1f));

            var mergeLabel = context.Label();

            if (context.Config.Stage == ShaderStage.Fragment)
            {
                var scaledInterpolatedLabel    = context.Label();
                var scaledNoInterpolationLabel = context.Label();

                var needsInterpolation = context.FOrdLessThan(context.TypeBool(), scale, context.Constant(context.TypeFP32(), 0f));

                context.SelectionMerge(mergeLabel, SelectionControlMask.MaskNone);
                context.BranchConditional(needsInterpolation, scaledInterpolatedLabel, scaledNoInterpolationLabel);

                // scale < 0.0
                context.AddLabel(scaledInterpolatedLabel);

                ApplyScalingInterpolated(context, localVector, vector, scale);
                context.Branch(mergeLabel);

                // scale >= 0.0
                context.AddLabel(scaledNoInterpolationLabel);

                ApplyScalingNoInterpolation(context, localVector, vector, scale);
                context.Branch(mergeLabel);

                context.AddLabel(mergeLabel);

                var passthroughLabel = context.Label();
                var finalMergeLabel  = context.Label();

                context.SelectionMerge(finalMergeLabel, SelectionControlMask.MaskNone);
                context.BranchConditional(passthrough, passthroughLabel, finalMergeLabel);

                context.AddLabel(passthroughLabel);

                context.Store(localVector, vector);
                context.Branch(finalMergeLabel);

                context.AddLabel(finalMergeLabel);

                return(context.Load(ivector2Type, localVector));
            }
            else
            {
                var passthroughLabel = context.Label();
                var scaledLabel      = context.Label();

                context.SelectionMerge(mergeLabel, SelectionControlMask.MaskNone);
                context.BranchConditional(passthrough, passthroughLabel, scaledLabel);

                // scale == 1.0
                context.AddLabel(passthroughLabel);

                context.Store(localVector, vector);
                context.Branch(mergeLabel);

                // scale != 1.0
                context.AddLabel(scaledLabel);

                ApplyScalingNoInterpolation(context, localVector, vector, scale);
                context.Branch(mergeLabel);

                context.AddLabel(mergeLabel);

                return(context.Load(ivector2Type, localVector));
            }
        }