public static string ToGlslString(this InputTopology topology) { return(topology switch { InputTopology.Points => "points", InputTopology.Lines => "lines", InputTopology.LinesAdjacency => "lines_adjacency", InputTopology.Triangles => "triangles", InputTopology.TrianglesAdjacency => "triangles_adjacency", _ => "points" });
public Pipeline CompilePipeline(InputTopology topology, params ShaderSource[] shaders) { var vs = shaders.FirstOrDefault(s => s.ShaderTypes.HasFlag(ShaderType.Vertex)); var gs = shaders.FirstOrDefault(s => s.ShaderTypes.HasFlag(ShaderType.Geometry)); var ps = shaders.FirstOrDefault(s => s.ShaderTypes.HasFlag(ShaderType.Pixel)); if (ps == null) { throw new ArgumentException("There must be one PixelShader"); } return(CompilePipeline(vs, gs, ps, topology)); }
public static string ToGlslString(this InputTopology topology) { switch (topology) { case InputTopology.Points: return("points"); case InputTopology.Lines: return("lines"); case InputTopology.LinesAdjacency: return("lines_adjacency"); case InputTopology.Triangles: return("triangles"); case InputTopology.TrianglesAdjacency: return("triangles_adjacency"); } return("points"); }
internal Pipeline(LightDevice device, IntPtr v, IntPtr g, IntPtr p, IntPtr sign, InputTopology topology) { _device = device; device.AddComponent(this); _device.ResolutionChanged += DeviceBufferResized; _vertex = v; _geometry = g; _pixel = p; _signatureBlob = sign; _viewport = new Viewport { Width = _device.ScreenWidth, Height = _device.ScreenHeight, MaxDepth = 1.0f, }; _topology = topology; }
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}\".") });
public static void Declare(CodeGenContext context, StructuredProgramInfo info) { context.AppendLine(context.Config.Options.TargetApi == TargetApi.Vulkan ? "#version 460 core" : "#version 450 core"); context.AppendLine("#extension GL_ARB_gpu_shader_int64 : enable"); if (context.Config.GpuAccessor.QueryHostSupportsShaderBallot()) { context.AppendLine("#extension GL_ARB_shader_ballot : enable"); } else { context.AppendLine("#extension GL_KHR_shader_subgroup_basic : enable"); context.AppendLine("#extension GL_KHR_shader_subgroup_ballot : enable"); } context.AppendLine("#extension GL_ARB_shader_group_vote : enable"); context.AppendLine("#extension GL_EXT_shader_image_load_formatted : enable"); context.AppendLine("#extension GL_EXT_texture_shadow_lod : enable"); if (context.Config.Stage == ShaderStage.Compute) { context.AppendLine("#extension GL_ARB_compute_shader : enable"); } else if (context.Config.Stage == ShaderStage.Fragment) { if (context.Config.GpuAccessor.QueryHostSupportsFragmentShaderInterlock()) { context.AppendLine("#extension GL_ARB_fragment_shader_interlock : enable"); } else if (context.Config.GpuAccessor.QueryHostSupportsFragmentShaderOrderingIntel()) { context.AppendLine("#extension GL_INTEL_fragment_shader_ordering : enable"); } } else { context.AppendLine("#extension GL_ARB_shader_viewport_layer_array : enable"); } if (context.Config.GpPassthrough && context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough()) { context.AppendLine("#extension GL_NV_geometry_shader_passthrough : enable"); } context.AppendLine("#pragma optionNV(fastmath off)"); context.AppendLine(); context.AppendLine($"const int {DefaultNames.UndefinedName} = 0;"); context.AppendLine(); if (context.Config.Stage == ShaderStage.Compute) { int localMemorySize = BitUtils.DivRoundUp(context.Config.GpuAccessor.QueryComputeLocalMemorySize(), 4); if (localMemorySize != 0) { string localMemorySizeStr = NumberFormatter.FormatInt(localMemorySize); context.AppendLine($"uint {DefaultNames.LocalMemoryName}[{localMemorySizeStr}];"); context.AppendLine(); } int sharedMemorySize = BitUtils.DivRoundUp(context.Config.GpuAccessor.QueryComputeSharedMemorySize(), 4); if (sharedMemorySize != 0) { string sharedMemorySizeStr = NumberFormatter.FormatInt(sharedMemorySize); context.AppendLine($"shared uint {DefaultNames.SharedMemoryName}[{sharedMemorySizeStr}];"); context.AppendLine(); } } else if (context.Config.LocalMemorySize != 0) { int localMemorySize = BitUtils.DivRoundUp(context.Config.LocalMemorySize, 4); string localMemorySizeStr = NumberFormatter.FormatInt(localMemorySize); context.AppendLine($"uint {DefaultNames.LocalMemoryName}[{localMemorySizeStr}];"); context.AppendLine(); } var cBufferDescriptors = context.Config.GetConstantBufferDescriptors(); if (cBufferDescriptors.Length != 0) { DeclareUniforms(context, cBufferDescriptors); context.AppendLine(); } var sBufferDescriptors = context.Config.GetStorageBufferDescriptors(); if (sBufferDescriptors.Length != 0) { DeclareStorages(context, sBufferDescriptors); context.AppendLine(); } var textureDescriptors = context.Config.GetTextureDescriptors(); if (textureDescriptors.Length != 0) { DeclareSamplers(context, textureDescriptors); context.AppendLine(); } var imageDescriptors = context.Config.GetImageDescriptors(); if (imageDescriptors.Length != 0) { DeclareImages(context, imageDescriptors); context.AppendLine(); } if (context.Config.Stage != ShaderStage.Compute) { if (context.Config.Stage == ShaderStage.Geometry) { InputTopology inputTopology = context.Config.GpuAccessor.QueryPrimitiveTopology(); string inPrimitive = inputTopology.ToGlslString(); context.AppendLine($"layout (invocations = {context.Config.ThreadsPerInputPrimitive}, {inPrimitive}) in;"); if (context.Config.GpPassthrough && context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough()) { context.AppendLine($"layout (passthrough) in gl_PerVertex"); context.EnterScope(); context.AppendLine("vec4 gl_Position;"); context.AppendLine("float gl_PointSize;"); context.AppendLine("float gl_ClipDistance[];"); context.LeaveScope(";"); } else { string outPrimitive = context.Config.OutputTopology.ToGlslString(); int maxOutputVertices = context.Config.GpPassthrough ? inputTopology.ToInputVertices() : context.Config.MaxOutputVertices; context.AppendLine($"layout ({outPrimitive}, max_vertices = {maxOutputVertices}) out;"); } context.AppendLine(); } else if (context.Config.Stage == ShaderStage.TessellationControl) { int threadsPerInputPrimitive = context.Config.ThreadsPerInputPrimitive; context.AppendLine($"layout (vertices = {threadsPerInputPrimitive}) out;"); context.AppendLine(); } else if (context.Config.Stage == ShaderStage.TessellationEvaluation) { string patchType = context.Config.GpuAccessor.QueryTessPatchType().ToGlsl(); string spacing = context.Config.GpuAccessor.QueryTessSpacing().ToGlsl(); string windingOrder = context.Config.GpuAccessor.QueryTessCw() ? "cw" : "ccw"; context.AppendLine($"layout ({patchType}, {spacing}, {windingOrder}) in;"); context.AppendLine(); } if (context.Config.UsedInputAttributes != 0 || context.Config.GpPassthrough) { DeclareInputAttributes(context, info); context.AppendLine(); } if (context.Config.UsedOutputAttributes != 0 || context.Config.Stage != ShaderStage.Fragment) { DeclareOutputAttributes(context, info); context.AppendLine(); } if (context.Config.UsedInputAttributesPerPatch != 0) { DeclareInputAttributesPerPatch(context, context.Config.UsedInputAttributesPerPatch); context.AppendLine(); } if (context.Config.UsedOutputAttributesPerPatch != 0) { DeclareUsedOutputAttributesPerPatch(context, context.Config.UsedOutputAttributesPerPatch); context.AppendLine(); } if (context.Config.TransformFeedbackEnabled && context.Config.LastInVertexPipeline) { var tfOutput = context.GetTransformFeedbackOutput(AttributeConsts.PositionX); if (tfOutput.Valid) { context.AppendLine($"layout (xfb_buffer = {tfOutput.Buffer}, xfb_offset = {tfOutput.Offset}, xfb_stride = {tfOutput.Stride}) out gl_PerVertex"); context.EnterScope(); context.AppendLine("vec4 gl_Position;"); context.LeaveScope(context.Config.Stage == ShaderStage.TessellationControl ? " gl_out[];" : ";"); } } } else { string localSizeX = NumberFormatter.FormatInt(context.Config.GpuAccessor.QueryComputeLocalSizeX()); string localSizeY = NumberFormatter.FormatInt(context.Config.GpuAccessor.QueryComputeLocalSizeY()); string localSizeZ = NumberFormatter.FormatInt(context.Config.GpuAccessor.QueryComputeLocalSizeZ()); context.AppendLine( "layout (" + $"local_size_x = {localSizeX}, " + $"local_size_y = {localSizeY}, " + $"local_size_z = {localSizeZ}) in;"); context.AppendLine(); } bool isFragment = context.Config.Stage == ShaderStage.Fragment; if (isFragment || context.Config.Stage == ShaderStage.Compute || context.Config.Stage == ShaderStage.Vertex) { if (isFragment && context.Config.GpuAccessor.QueryEarlyZForce()) { context.AppendLine("layout(early_fragment_tests) in;"); context.AppendLine(); } if ((context.Config.UsedFeatures & (FeatureFlags.FragCoordXY | FeatureFlags.IntegerSampling)) != 0) { string stage = OperandManager.GetShaderStagePrefix(context.Config.Stage); int scaleElements = context.Config.GetTextureDescriptors().Length + context.Config.GetImageDescriptors().Length; if (isFragment) { scaleElements++; // Also includes render target scale, for gl_FragCoord. } DeclareSupportUniformBlock(context, context.Config.Stage, scaleElements); if (context.Config.UsedFeatures.HasFlag(FeatureFlags.IntegerSampling)) { AppendHelperFunction(context, $"Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_{stage}.glsl"); context.AppendLine(); } } else if (isFragment || context.Config.Stage == ShaderStage.Vertex) { DeclareSupportUniformBlock(context, context.Config.Stage, 0); } } if ((info.HelperFunctionsMask & HelperFunctionsMask.AtomicMinMaxS32Shared) != 0) { AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/AtomicMinMaxS32Shared.glsl"); } if ((info.HelperFunctionsMask & HelperFunctionsMask.AtomicMinMaxS32Storage) != 0) { AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/AtomicMinMaxS32Storage.glsl"); } if ((info.HelperFunctionsMask & HelperFunctionsMask.MultiplyHighS32) != 0) { AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/MultiplyHighS32.glsl"); } if ((info.HelperFunctionsMask & HelperFunctionsMask.MultiplyHighU32) != 0) { AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/MultiplyHighU32.glsl"); } if ((info.HelperFunctionsMask & HelperFunctionsMask.Shuffle) != 0) { AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/Shuffle.glsl"); } if ((info.HelperFunctionsMask & HelperFunctionsMask.ShuffleDown) != 0) { AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleDown.glsl"); } if ((info.HelperFunctionsMask & HelperFunctionsMask.ShuffleUp) != 0) { AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleUp.glsl"); } if ((info.HelperFunctionsMask & HelperFunctionsMask.ShuffleXor) != 0) { AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleXor.glsl"); } if ((info.HelperFunctionsMask & HelperFunctionsMask.StoreSharedSmallInt) != 0) { AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/StoreSharedSmallInt.glsl"); } if ((info.HelperFunctionsMask & HelperFunctionsMask.StoreStorageSmallInt) != 0) { AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/StoreStorageSmallInt.glsl"); } if ((info.HelperFunctionsMask & HelperFunctionsMask.SwizzleAdd) != 0) { AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/SwizzleAdd.glsl"); } }
private unsafe Pipeline CompilePipeline(ShaderSource srcVS, ShaderSource srcGS, ShaderSource srcPS, InputTopology topology) { using (ComScopeGuard vertexShader = new ComScopeGuard(), pixelShader = new ComScopeGuard(), geometryShader = new ComScopeGuard(), signatureBlob = new ComScopeGuard()) { if (srcVS != null) fixed(byte *codePtr = srcVS.Data) { using (var blob = new ComScopeGuard()) { blob.Ptr = Compile(codePtr, srcVS.Data.Length, CompilerStringConstants.VS, CompilerStringConstants.vs_4_0); Device.CreateVertexShader(_device, Blob.GetBufferPointer(blob.Ptr), Blob.GetBufferSize(blob.Ptr), IntPtr.Zero, out vertexShader.Ptr); Native.D3DGetInputSignatureBlob( Blob.GetBufferPointer(blob.Ptr), Blob.GetBufferSize(blob.Ptr), out signatureBlob.Ptr); } } if (srcGS != null) fixed(byte *codePtr = srcGS.Data) { using (var blob = new ComScopeGuard()) { blob.Ptr = Compile(codePtr, srcGS.Data.Length, CompilerStringConstants.GS, CompilerStringConstants.gs_4_0); Device.CreateGeometryShader(_device, Blob.GetBufferPointer(blob.Ptr), Blob.GetBufferSize(blob.Ptr), IntPtr.Zero, out geometryShader.Ptr); } } fixed(byte *codePtr = srcPS.Data) { using (var blob = new ComScopeGuard()) { blob.Ptr = Compile(codePtr, srcPS.Data.Length, CompilerStringConstants.PS, CompilerStringConstants.ps_4_0); Device.CreatePixelShader(_device, Blob.GetBufferPointer(blob.Ptr), Blob.GetBufferSize(blob.Ptr), IntPtr.Zero, out pixelShader.Ptr); } } return(new Pipeline(this, vertexShader.Move(), geometryShader.Move(), pixelShader.Move(), signatureBlob.Move(), topology)); } //using }
public static void S2r(EmitterContext context) { InstS2r op = context.GetOp <InstS2r>(); Operand src; switch (op.SReg) { case SReg.LaneId: src = Attribute(AttributeConsts.LaneId); break; case SReg.InvocationId: src = Attribute(AttributeConsts.InvocationId); break; case SReg.YDirection: src = ConstF(1); // TODO: Use value from Y direction GPU register. break; case SReg.ThreadKill: src = context.Config.Stage == ShaderStage.Fragment ? Attribute(AttributeConsts.ThreadKill) : Const(0); break; case SReg.InvocationInfo: if (context.Config.Stage != ShaderStage.Compute && context.Config.Stage != ShaderStage.Fragment) { Operand primitiveId = Attribute(AttributeConsts.PrimitiveId); Operand patchVerticesIn; if (context.Config.Stage == ShaderStage.TessellationEvaluation) { patchVerticesIn = context.ShiftLeft(Attribute(AttributeConsts.PatchVerticesIn), Const(16)); } else { InputTopology inputTopology = context.Config.GpuAccessor.QueryPrimitiveTopology(); int inputVertices = inputTopology switch { InputTopology.Points => 1, InputTopology.Lines or InputTopology.LinesAdjacency => 2, InputTopology.Triangles or InputTopology.TrianglesAdjacency => 3, _ => 1 }; patchVerticesIn = Const(inputVertices << 16); } src = context.BitwiseOr(primitiveId, patchVerticesIn); } else { src = Const(0); } break; case SReg.TId: Operand tidX = Attribute(AttributeConsts.ThreadIdX); Operand tidY = Attribute(AttributeConsts.ThreadIdY); Operand tidZ = Attribute(AttributeConsts.ThreadIdZ); tidY = context.ShiftLeft(tidY, Const(16)); tidZ = context.ShiftLeft(tidZ, Const(26)); src = context.BitwiseOr(tidX, context.BitwiseOr(tidY, tidZ)); break; case SReg.TIdX: src = Attribute(AttributeConsts.ThreadIdX); break; case SReg.TIdY: src = Attribute(AttributeConsts.ThreadIdY); break; case SReg.TIdZ: src = Attribute(AttributeConsts.ThreadIdZ); break; case SReg.CtaIdX: src = Attribute(AttributeConsts.CtaIdX); break; case SReg.CtaIdY: src = Attribute(AttributeConsts.CtaIdY); break; case SReg.CtaIdZ: src = Attribute(AttributeConsts.CtaIdZ); break; case SReg.EqMask: src = Attribute(AttributeConsts.EqMask); break; case SReg.LtMask: src = Attribute(AttributeConsts.LtMask); break; case SReg.LeMask: src = Attribute(AttributeConsts.LeMask); break; case SReg.GtMask: src = Attribute(AttributeConsts.GtMask); break; case SReg.GeMask: src = Attribute(AttributeConsts.GeMask); break; default: src = Const(0); break; } context.Copy(GetDest(op.Dest), src); }