public static void DeclareParameters(CodeGenContext context, StructuredFunction function) { DeclareParameters(context, function.InArguments, 0); DeclareParameters(context, function.OutArguments, function.InArguments.Length); }
private static void DeclareSharedMemory(CodeGenContext context, int size) { context.SharedMemory = DeclareMemory(context, StorageClass.Workgroup, size); }
private static void DeclareLocalMemory(CodeGenContext context, int size) { context.LocalMemory = DeclareMemory(context, StorageClass.Private, size); }
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); }
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}\".") });
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)); } }