diff --git a/src/Ryujinx.Graphics.Metal/HelperShaders.cs b/src/Ryujinx.Graphics.Metal/HelperShaders.cs new file mode 100644 index 000000000..0864839fd --- /dev/null +++ b/src/Ryujinx.Graphics.Metal/HelperShaders.cs @@ -0,0 +1,59 @@ +using Ryujinx.Common; +using Ryujinx.Common.Logging; +using SharpMetal.Foundation; +using SharpMetal.Metal; +using System; +using System.Runtime.Versioning; + +namespace Ryujinx.Graphics.Metal +{ + [SupportedOSPlatform("macos")] + public class HelperShaders + { + private const string ShadersSourcePath = "/Ryujinx.Graphics.Metal/HelperShadersSource.metal"; + + public HelperShader BlitShader; + + public HelperShaders(MTLDevice device) + { + var error = new NSError(IntPtr.Zero); + + var shaderSource = EmbeddedResources.ReadAllText(ShadersSourcePath); + var library = device.NewLibrary(StringHelper.NSString(shaderSource), new(IntPtr.Zero), ref error); + if (error != IntPtr.Zero) + { + Logger.Error?.PrintMsg(LogClass.Gpu, $"Failed to create Library: {StringHelper.String(error.LocalizedDescription)}"); + } + + BlitShader = new HelperShader(device, library, "vertexBlit", "fragmentBlit"); + } + } + + [SupportedOSPlatform("macos")] + public struct HelperShader + { + private MTLRenderPipelineState _pipelineState; + public static implicit operator MTLRenderPipelineState(HelperShader shader) => shader._pipelineState; + + public HelperShader(MTLDevice device, MTLLibrary library, string vertex, string fragment) + { + var renderPipelineDescriptor = new MTLRenderPipelineDescriptor(); + + renderPipelineDescriptor.VertexFunction = library.NewFunction(StringHelper.NSString(vertex));; + renderPipelineDescriptor.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)}"); + } + } + } +} diff --git a/src/Ryujinx.Graphics.Metal/Shaders/ColorBlitShaderSource.metal b/src/Ryujinx.Graphics.Metal/HelperShadersSource.metal similarity index 77% rename from src/Ryujinx.Graphics.Metal/Shaders/ColorBlitShaderSource.metal rename to src/Ryujinx.Graphics.Metal/HelperShadersSource.metal index a1630e7b8..7d3c9eb89 100644 --- a/src/Ryujinx.Graphics.Metal/Shaders/ColorBlitShaderSource.metal +++ b/src/Ryujinx.Graphics.Metal/HelperShadersSource.metal @@ -16,7 +16,7 @@ struct CopyVertexOut { float2 uv; }; -vertex CopyVertexOut vertexMain(unsigned short vid [[vertex_id]]) { +vertex CopyVertexOut vertexBlit(unsigned short vid [[vertex_id]]) { float2 position = quadVertices[vid]; CopyVertexOut out; @@ -28,8 +28,8 @@ vertex CopyVertexOut vertexMain(unsigned short vid [[vertex_id]]) { return out; } -fragment float4 fragmentMain(CopyVertexOut in [[stage_in]], - texture2d tex) { +fragment float4 fragmentBlit(CopyVertexOut in [[stage_in]], + texture2d tex) { constexpr sampler sam(min_filter::nearest, mag_filter::nearest, mip_filter::none); return tex.sample(sam, in.uv).xyzw; diff --git a/src/Ryujinx.Graphics.Metal/MetalRenderer.cs b/src/Ryujinx.Graphics.Metal/MetalRenderer.cs index 09960f9ab..d3d73f551 100644 --- a/src/Ryujinx.Graphics.Metal/MetalRenderer.cs +++ b/src/Ryujinx.Graphics.Metal/MetalRenderer.cs @@ -46,12 +46,12 @@ namespace Ryujinx.Graphics.Metal MTLCaptureManager.SharedCaptureManager().StartCapture(captureDescriptor, ref captureError); if (captureError != IntPtr.Zero) { - Console.Write($"Failed to start capture! {StringHelper.String(captureError.LocalizedDescription)}"); + Console.WriteLine($"Failed to start capture! {StringHelper.String(captureError.LocalizedDescription)}"); } _window = new Window(this, layer); - _pipeline = new Pipeline(_device, _queue, layer); + _pipeline = new Pipeline(_device, _queue); } public void BackgroundContextAction(Action action, bool alwaysBackground = false) diff --git a/src/Ryujinx.Graphics.Metal/Pipeline.cs b/src/Ryujinx.Graphics.Metal/Pipeline.cs index 47d8f52ff..f101fa637 100644 --- a/src/Ryujinx.Graphics.Metal/Pipeline.cs +++ b/src/Ryujinx.Graphics.Metal/Pipeline.cs @@ -1,4 +1,3 @@ -using Ryujinx.Common; using Ryujinx.Common.Logging; using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.Shader; @@ -14,10 +13,9 @@ namespace Ryujinx.Graphics.Metal [SupportedOSPlatform("macos")] public class Pipeline : IPipeline, IDisposable { - private const string ShaderSourcePath = "Ryujinx.Graphics.Metal/Shaders"; - private readonly MTLDevice _device; private readonly MTLCommandQueue _mtlCommandQueue; + private readonly HelperShaders _helperShaders; private MTLCommandBuffer _commandBuffer; private MTLCommandEncoder _currentEncoder; @@ -32,43 +30,13 @@ namespace Ryujinx.Graphics.Metal private MTLClearColor _clearColor; private int frameCount = 0; - public Pipeline(MTLDevice device, MTLCommandQueue commandQueue, CAMetalLayer metalLayer) + public Pipeline(MTLDevice device, MTLCommandQueue commandQueue) { _device = device; _mtlCommandQueue = commandQueue; + _helperShaders = new HelperShaders(_device); - var error = new NSError(IntPtr.Zero); - - var shaderSource = EmbeddedResources.ReadAllText(string.Join('/', ShaderSourcePath, "ColorBlitShaderSource.metal")); - var library = _device.NewLibrary(StringHelper.NSString(shaderSource), new(IntPtr.Zero), ref error); - if (error != IntPtr.Zero) - { - Logger.Error?.PrintMsg(LogClass.Gpu, $"Failed to create Library: {StringHelper.String(error.LocalizedDescription)}"); - } - - var vertexFunction = library.NewFunction(StringHelper.NSString("vertexMain")); - var fragmentFunction = library.NewFunction(StringHelper.NSString("fragmentMain")); - - // TODO: Recreate descriptor and encoder state as needed - var renderPipelineDescriptor = new MTLRenderPipelineDescriptor(); - renderPipelineDescriptor.VertexFunction = vertexFunction; - renderPipelineDescriptor.FragmentFunction = fragmentFunction; - // TODO: This should not be hardcoded, but a bug in SharpMetal prevents me from doing this correctly - 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 renderPipelineState = _device.NewRenderPipelineState(renderPipelineDescriptor, ref error); - if (error != IntPtr.Zero) - { - Logger.Error?.PrintMsg(LogClass.Gpu, $"Failed to create Render Pipeline State: {StringHelper.String(error.LocalizedDescription)}"); - } - - _renderEncoderState = new RenderEncoderState(renderPipelineState, _device); - // + _renderEncoderState = new RenderEncoderState(_helperShaders.BlitShader, _device); _commandBuffer = _mtlCommandQueue.CommandBuffer(); } diff --git a/src/Ryujinx.Graphics.Metal/Ryujinx.Graphics.Metal.csproj b/src/Ryujinx.Graphics.Metal/Ryujinx.Graphics.Metal.csproj index 638e1db67..529666b9d 100644 --- a/src/Ryujinx.Graphics.Metal/Ryujinx.Graphics.Metal.csproj +++ b/src/Ryujinx.Graphics.Metal/Ryujinx.Graphics.Metal.csproj @@ -10,12 +10,12 @@ - - - - + + + + \ No newline at end of file