diff --git a/src/Ryujinx.Graphics.Metal/MetalRenderer.cs b/src/Ryujinx.Graphics.Metal/MetalRenderer.cs index 18f11e583..5ecaf7575 100644 --- a/src/Ryujinx.Graphics.Metal/MetalRenderer.cs +++ b/src/Ryujinx.Graphics.Metal/MetalRenderer.cs @@ -74,8 +74,7 @@ namespace Ryujinx.Graphics.Metal public IProgram CreateProgram(ShaderSource[] shaders, ShaderInfo info) { - Logger.Warning?.Print(LogClass.Gpu, "Not Implemented!"); - return new Program(); + return new Program(shaders, _device); } public ISampler CreateSampler(SamplerCreateInfo info) diff --git a/src/Ryujinx.Graphics.Metal/Program.cs b/src/Ryujinx.Graphics.Metal/Program.cs index a7953dde1..6cf2a96e5 100644 --- a/src/Ryujinx.Graphics.Metal/Program.cs +++ b/src/Ryujinx.Graphics.Metal/Program.cs @@ -1,12 +1,59 @@ +using Ryujinx.Common.Logging; using Ryujinx.Graphics.GAL; +using Ryujinx.Graphics.Shader; +using SharpMetal.Foundation; +using SharpMetal.Metal; +using System; +using System.Runtime.Versioning; namespace Ryujinx.Graphics.Metal { + [SupportedOSPlatform("macos")] class Program : IProgram { + private ProgramLinkStatus _status = ProgramLinkStatus.Incomplete; + private MTLFunction[] _shaderHandles; + + 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); + ShaderSource shader = shaders[index]; + var shaderLibrary = device.NewLibrary(StringHelper.NSString(shader.Code), new MTLCompileOptions(IntPtr.Zero), ref libraryError); + if (libraryError != IntPtr.Zero) + { + Logger.Warning?.Print(LogClass.Gpu, $"Shader linking failed: \n{StringHelper.String(libraryError.LocalizedDescription)}"); + _status = ProgramLinkStatus.Failure; + } + else + { + switch (shaders[index].Stage) + { + case ShaderStage.Compute: + _shaderHandles[index] = shaderLibrary.NewFunction(StringHelper.NSString("computeMain")); + break; + case ShaderStage.Vertex: + _shaderHandles[index] = shaderLibrary.NewFunction(StringHelper.NSString("vertexMain")); + break; + case ShaderStage.Fragment: + _shaderHandles[index] = shaderLibrary.NewFunction(StringHelper.NSString("fragmentMain")); + break; + default: + Logger.Warning?.Print(LogClass.Gpu, $"Cannot handle stage {shaders[index].Stage}!"); + break; + } + + _status = ProgramLinkStatus.Success; + } + } + } + public ProgramLinkStatus CheckProgramLink(bool blocking) { - return ProgramLinkStatus.Success; + return _status; } public byte[] GetBinary()