diff --git a/src/Ryujinx.Graphics.Metal/HelperShaders.cs b/src/Ryujinx.Graphics.Metal/HelperShaders.cs index a4517b7ce..7c1eada7b 100644 --- a/src/Ryujinx.Graphics.Metal/HelperShaders.cs +++ b/src/Ryujinx.Graphics.Metal/HelperShaders.cs @@ -32,29 +32,13 @@ namespace Ryujinx.Graphics.Metal [SupportedOSPlatform("macos")] public readonly struct HelperShader { - private readonly MTLRenderPipelineState _pipelineState; - public static implicit operator MTLRenderPipelineState(HelperShader shader) => shader._pipelineState; + public readonly MTLFunction VertexFunction; + public readonly MTLFunction FragmentFunction; public HelperShader(MTLDevice device, MTLLibrary library, string vertex, string fragment) { - var renderPipelineDescriptor = new MTLRenderPipelineDescriptor - { - VertexFunction = library.NewFunction(StringHelper.NSString(vertex)), - FragmentFunction = library.NewFunction(StringHelper.NSString(fragment)) - }; - renderPipelineDescriptor.ColorAttachments.Object(0).SetBlendingEnabled(true); - renderPipelineDescriptor.ColorAttachments.Object(0).PixelFormat = MTLPixelFormat.BGRA8Unorm; - renderPipelineDescriptor.ColorAttachments.Object(0).SourceAlphaBlendFactor = MTLBlendFactor.SourceAlpha; - renderPipelineDescriptor.ColorAttachments.Object(0).DestinationAlphaBlendFactor = MTLBlendFactor.OneMinusSourceAlpha; - renderPipelineDescriptor.ColorAttachments.Object(0).SourceRGBBlendFactor = MTLBlendFactor.SourceAlpha; - renderPipelineDescriptor.ColorAttachments.Object(0).DestinationRGBBlendFactor = MTLBlendFactor.OneMinusSourceAlpha; - - var error = new NSError(IntPtr.Zero); - _pipelineState = device.NewRenderPipelineState(renderPipelineDescriptor, ref error); - if (error != IntPtr.Zero) - { - Logger.Error?.PrintMsg(LogClass.Gpu, $"Failed to create Render Pipeline State: {StringHelper.String(error.LocalizedDescription)}"); - } + VertexFunction = library.NewFunction(StringHelper.NSString(vertex)); + FragmentFunction = library.NewFunction(StringHelper.NSString(fragment)); } } } diff --git a/src/Ryujinx.Graphics.Metal/Pipeline.cs b/src/Ryujinx.Graphics.Metal/Pipeline.cs index 2c1e0d4e3..93f463418 100644 --- a/src/Ryujinx.Graphics.Metal/Pipeline.cs +++ b/src/Ryujinx.Graphics.Metal/Pipeline.cs @@ -40,7 +40,10 @@ namespace Ryujinx.Graphics.Metal _commandQueue = commandQueue; _helperShaders = new HelperShaders(_device); - _renderEncoderState = new RenderEncoderState(_helperShaders.BlitShader, _device); + _renderEncoderState = new RenderEncoderState( + _helperShaders.BlitShader.VertexFunction, + _helperShaders.BlitShader.FragmentFunction, + _device); _commandBuffer = _commandQueue.CommandBuffer(); @@ -424,7 +427,12 @@ namespace Ryujinx.Graphics.Metal public void SetProgram(IProgram program) { - Logger.Warning?.Print(LogClass.Gpu, "Not Implemented!"); + Program prg = (Program)program; + + _renderEncoderState = new RenderEncoderState( + prg.VertexFunction, + prg.FragmentFunction, + _device); } public void SetRasterizerDiscard(bool discard) @@ -523,7 +531,7 @@ namespace Ryujinx.Graphics.Metal public void SetVertexBuffers(ReadOnlySpan vertexBuffers) { - Logger.Warning?.Print(LogClass.Gpu, "Not Implemented!"); + _renderEncoderState.UpdateVertexDescriptor(vertexBuffers); } public unsafe void SetViewports(ReadOnlySpan viewports) diff --git a/src/Ryujinx.Graphics.Metal/Program.cs b/src/Ryujinx.Graphics.Metal/Program.cs index 6cf2a96e5..7a7eb5836 100644 --- a/src/Ryujinx.Graphics.Metal/Program.cs +++ b/src/Ryujinx.Graphics.Metal/Program.cs @@ -12,12 +12,12 @@ namespace Ryujinx.Graphics.Metal class Program : IProgram { private ProgramLinkStatus _status = ProgramLinkStatus.Incomplete; - private MTLFunction[] _shaderHandles; + public MTLFunction VertexFunction; + public MTLFunction FragmentFunction; + public MTLFunction ComputeFunction; public Program(ShaderSource[] shaders, MTLDevice device) { - _shaderHandles = new MTLFunction[shaders.Length]; - for (int index = 0; index < shaders.Length; index++) { var libraryError = new NSError(IntPtr.Zero); @@ -33,13 +33,13 @@ namespace Ryujinx.Graphics.Metal switch (shaders[index].Stage) { case ShaderStage.Compute: - _shaderHandles[index] = shaderLibrary.NewFunction(StringHelper.NSString("computeMain")); + ComputeFunction = shaderLibrary.NewFunction(StringHelper.NSString("computeMain")); break; case ShaderStage.Vertex: - _shaderHandles[index] = shaderLibrary.NewFunction(StringHelper.NSString("vertexMain")); + VertexFunction = shaderLibrary.NewFunction(StringHelper.NSString("vertexMain")); break; case ShaderStage.Fragment: - _shaderHandles[index] = shaderLibrary.NewFunction(StringHelper.NSString("fragmentMain")); + FragmentFunction = shaderLibrary.NewFunction(StringHelper.NSString("fragmentMain")); break; default: Logger.Warning?.Print(LogClass.Gpu, $"Cannot handle stage {shaders[index].Stage}!"); diff --git a/src/Ryujinx.Graphics.Metal/RenderEncoderState.cs b/src/Ryujinx.Graphics.Metal/RenderEncoderState.cs index e24b49090..c394ba385 100644 --- a/src/Ryujinx.Graphics.Metal/RenderEncoderState.cs +++ b/src/Ryujinx.Graphics.Metal/RenderEncoderState.cs @@ -1,4 +1,6 @@ +using Ryujinx.Common.Logging; using Ryujinx.Graphics.GAL; +using SharpMetal.Foundation; using SharpMetal.Metal; using System; using System.Runtime.Versioning; @@ -9,8 +11,8 @@ namespace Ryujinx.Graphics.Metal struct RenderEncoderState { private readonly MTLDevice _device; - // TODO: Work with more than one pipeline state - private readonly MTLRenderPipelineState _copyPipeline; + private readonly MTLFunction _vertexFunction = null; + private readonly MTLFunction _fragmentFunction = null; private MTLDepthStencilState _depthStencilState = null; private MTLCompareFunction _depthCompareFunction = MTLCompareFunction.Always; @@ -19,19 +21,51 @@ namespace Ryujinx.Graphics.Metal private MTLStencilDescriptor _backFaceStencil = null; private MTLStencilDescriptor _frontFaceStencil = null; + private MTLVertexDescriptor _vertexDescriptor = new(); + public PrimitiveTopology Topology = PrimitiveTopology.Triangles; public MTLCullMode CullMode = MTLCullMode.None; public MTLWinding Winding = MTLWinding.Clockwise; - public RenderEncoderState(MTLRenderPipelineState copyPipeline, MTLDevice device) + public RenderEncoderState(MTLFunction vertexFunction, MTLFunction fragmentFunction, MTLDevice device) { + _vertexFunction = vertexFunction; + _fragmentFunction = fragmentFunction; _device = device; - _copyPipeline = copyPipeline; } public readonly void SetEncoderState(MTLRenderCommandEncoder renderCommandEncoder) { - renderCommandEncoder.SetRenderPipelineState(_copyPipeline); + var renderPipelineDescriptor = new MTLRenderPipelineDescriptor + { + VertexDescriptor = _vertexDescriptor + }; + + if (_vertexFunction != null) + { + renderPipelineDescriptor.VertexFunction = _vertexFunction; + } + + if (_fragmentFunction != null) + { + renderPipelineDescriptor.VertexFunction = _fragmentFunction; + } + + renderPipelineDescriptor.ColorAttachments.Object(0).SetBlendingEnabled(true); + renderPipelineDescriptor.ColorAttachments.Object(0).PixelFormat = MTLPixelFormat.BGRA8Unorm; + renderPipelineDescriptor.ColorAttachments.Object(0).SourceAlphaBlendFactor = MTLBlendFactor.SourceAlpha; + renderPipelineDescriptor.ColorAttachments.Object(0).DestinationAlphaBlendFactor = MTLBlendFactor.OneMinusSourceAlpha; + renderPipelineDescriptor.ColorAttachments.Object(0).SourceRGBBlendFactor = MTLBlendFactor.SourceAlpha; + renderPipelineDescriptor.ColorAttachments.Object(0).DestinationRGBBlendFactor = MTLBlendFactor.OneMinusSourceAlpha; + + var error = new NSError(IntPtr.Zero); + var pipelineState = _device.NewRenderPipelineState(renderPipelineDescriptor, ref error); + if (error != IntPtr.Zero) + { + Logger.Error?.PrintMsg(LogClass.Gpu, $"Failed to create Render Pipeline State: {StringHelper.String(error.LocalizedDescription)}"); + } + + renderCommandEncoder.SetRenderPipelineState(pipelineState); renderCommandEncoder.SetCullMode(CullMode); renderCommandEncoder.SetFrontFacingWinding(Winding); @@ -68,5 +102,21 @@ namespace Ryujinx.Graphics.Metal FrontFaceStencil = _frontFaceStencil }); } + + public void UpdateVertexDescriptor(ReadOnlySpan vertexBuffers) + { + _vertexDescriptor = new(); + + for (int i = 0; i < vertexBuffers.Length; i++) + { + if (vertexBuffers[i].Stride != 0) + { + // TODO: Format should not be hardcoded + _vertexDescriptor.Attributes.Object((ulong)i).Format = MTLVertexFormat.Float4; + _vertexDescriptor.Attributes.Object((ulong)i).BufferIndex = (ulong)i; + _vertexDescriptor.Layouts.Object((ulong)i).Stride = (ulong)vertexBuffers[i].Stride; + } + } + } } }