diff --git a/src/Ryujinx.Graphics.Metal/HelperShader.cs b/src/Ryujinx.Graphics.Metal/HelperShader.cs index 7e20ec2216..87d720c5e4 100644 --- a/src/Ryujinx.Graphics.Metal/HelperShader.cs +++ b/src/Ryujinx.Graphics.Metal/HelperShader.cs @@ -21,9 +21,15 @@ namespace Ryujinx.Graphics.Metal private readonly ISampler _samplerLinear; private readonly ISampler _samplerNearest; - private readonly IProgram _programColorBlit; - private readonly IProgram _programColorBlitMs; - private readonly List _programsColorClear = new(); + private readonly IProgram _programColorBlitF; + private readonly IProgram _programColorBlitI; + private readonly IProgram _programColorBlitU; + private readonly IProgram _programColorBlitMsF; + private readonly IProgram _programColorBlitMsI; + private readonly IProgram _programColorBlitMsU; + private readonly List _programsColorClearF = new(); + private readonly List _programsColorClearI = new(); + private readonly List _programsColorClearU = new(); private readonly IProgram _programDepthStencilClear; private readonly IProgram _programStrideChange; private readonly IProgram _programDepthBlit; @@ -47,27 +53,80 @@ namespace Ryujinx.Graphics.Metal .Add(ResourceStages.Fragment, ResourceType.TextureAndSampler, 0).Build(); var blitSource = ReadMsl("Blit.metal"); - _programColorBlit = new Program( + + var blitSourceF = blitSource.Replace("FORMAT", "float", StringComparison.Ordinal); + _programColorBlitF = new Program( [ - new ShaderSource(blitSource, ShaderStage.Fragment, TargetLanguage.Msl), - new ShaderSource(blitSource, ShaderStage.Vertex, TargetLanguage.Msl) + new ShaderSource(blitSourceF, ShaderStage.Fragment, TargetLanguage.Msl), + new ShaderSource(blitSourceF, ShaderStage.Vertex, TargetLanguage.Msl) + ], blitResourceLayout, device); + + var blitSourceI = blitSource.Replace("FORMAT", "int"); + _programColorBlitI = new Program( + [ + new ShaderSource(blitSourceI, ShaderStage.Fragment, TargetLanguage.Msl), + new ShaderSource(blitSourceI, ShaderStage.Vertex, TargetLanguage.Msl) + ], blitResourceLayout, device); + + var blitSourceU = blitSource.Replace("FORMAT", "uint"); + _programColorBlitU = new Program( + [ + new ShaderSource(blitSourceU, ShaderStage.Fragment, TargetLanguage.Msl), + new ShaderSource(blitSourceU, ShaderStage.Vertex, TargetLanguage.Msl) ], blitResourceLayout, device); var blitMsSource = ReadMsl("BlitMs.metal"); - _programColorBlitMs = new Program( + + var blitMsSourceF = blitMsSource.Replace("FORMAT", "float"); + _programColorBlitMsF = new Program( [ - new ShaderSource(blitMsSource, ShaderStage.Fragment, TargetLanguage.Msl), - new ShaderSource(blitSource, ShaderStage.Vertex, TargetLanguage.Msl) + new ShaderSource(blitMsSourceF, ShaderStage.Fragment, TargetLanguage.Msl), + new ShaderSource(blitMsSourceF, ShaderStage.Vertex, TargetLanguage.Msl) + ], blitResourceLayout, device); + + var blitMsSourceI = blitMsSource.Replace("FORMAT", "int"); + _programColorBlitMsI = new Program( + [ + new ShaderSource(blitMsSourceI, ShaderStage.Fragment, TargetLanguage.Msl), + new ShaderSource(blitMsSourceI, ShaderStage.Vertex, TargetLanguage.Msl) + ], blitResourceLayout, device); + + var blitMsSourceU = blitMsSource.Replace("FORMAT", "uint"); + _programColorBlitMsU = new Program( + [ + new ShaderSource(blitMsSourceU, ShaderStage.Fragment, TargetLanguage.Msl), + new ShaderSource(blitMsSourceU, ShaderStage.Vertex, TargetLanguage.Msl) ], blitResourceLayout, device); var colorClearResourceLayout = new ResourceLayoutBuilder() .Add(ResourceStages.Fragment, ResourceType.UniformBuffer, 0).Build(); var colorClearSource = ReadMsl("ColorClear.metal"); + for (int i = 0; i < Constants.MaxColorAttachments; i++) { - var crntSource = colorClearSource.Replace("COLOR_ATTACHMENT_INDEX", i.ToString()); - _programsColorClear.Add(new Program( + var crntSource = colorClearSource.Replace("COLOR_ATTACHMENT_INDEX", i.ToString()).Replace("FORMAT", "float"); + _programsColorClearF.Add(new Program( + [ + new ShaderSource(crntSource, ShaderStage.Fragment, TargetLanguage.Msl), + new ShaderSource(crntSource, ShaderStage.Vertex, TargetLanguage.Msl) + ], colorClearResourceLayout, device)); + } + + for (int i = 0; i < Constants.MaxColorAttachments; i++) + { + var crntSource = colorClearSource.Replace("COLOR_ATTACHMENT_INDEX", i.ToString()).Replace("FORMAT", "int"); + _programsColorClearI.Add(new Program( + [ + new ShaderSource(crntSource, ShaderStage.Fragment, TargetLanguage.Msl), + new ShaderSource(crntSource, ShaderStage.Vertex, TargetLanguage.Msl) + ], colorClearResourceLayout, device)); + } + + for (int i = 0; i < Constants.MaxColorAttachments; i++) + { + var crntSource = colorClearSource.Replace("COLOR_ATTACHMENT_INDEX", i.ToString()).Replace("FORMAT", "uint"); + _programsColorClearU.Add(new Program( [ new ShaderSource(crntSource, ShaderStage.Fragment, TargetLanguage.Msl), new ShaderSource(crntSource, ShaderStage.Vertex, TargetLanguage.Msl) @@ -96,28 +155,28 @@ namespace Ryujinx.Graphics.Metal _programDepthBlit = new Program( [ new ShaderSource(depthBlitSource, ShaderStage.Fragment, TargetLanguage.Msl), - new ShaderSource(blitSource, ShaderStage.Vertex, TargetLanguage.Msl) + new ShaderSource(blitSourceF, ShaderStage.Vertex, TargetLanguage.Msl) ], blitResourceLayout, device); var depthBlitMsSource = ReadMsl("DepthBlitMs.metal"); _programDepthBlitMs = new Program( [ new ShaderSource(depthBlitMsSource, ShaderStage.Fragment, TargetLanguage.Msl), - new ShaderSource(blitSource, ShaderStage.Vertex, TargetLanguage.Msl) + new ShaderSource(blitSourceF, ShaderStage.Vertex, TargetLanguage.Msl) ], blitResourceLayout, device); var stencilBlitSource = ReadMsl("StencilBlit.metal"); _programStencilBlit = new Program( [ new ShaderSource(stencilBlitSource, ShaderStage.Fragment, TargetLanguage.Msl), - new ShaderSource(blitSource, ShaderStage.Vertex, TargetLanguage.Msl) + new ShaderSource(blitSourceF, ShaderStage.Vertex, TargetLanguage.Msl) ], blitResourceLayout, device); var stencilBlitMsSource = ReadMsl("StencilBlitMs.metal"); _programStencilBlitMs = new Program( [ new ShaderSource(stencilBlitMsSource, ShaderStage.Fragment, TargetLanguage.Msl), - new ShaderSource(blitSource, ShaderStage.Vertex, TargetLanguage.Msl) + new ShaderSource(blitSourceF, ShaderStage.Vertex, TargetLanguage.Msl) ], blitResourceLayout, device); } @@ -201,11 +260,33 @@ namespace Ryujinx.Graphics.Metal } else if (src.Info.Target.IsMultisample()) { - _pipeline.SetProgram(_programColorBlitMs); + if (dst.Info.Format.IsSint()) + { + _pipeline.SetProgram(_programColorBlitMsI); + } + else if (dst.Info.Format.IsUint()) + { + _pipeline.SetProgram(_programColorBlitMsU); + } + else + { + _pipeline.SetProgram(_programColorBlitMsF); + } } else { - _pipeline.SetProgram(_programColorBlit); + if (dst.Info.Format.IsSint()) + { + _pipeline.SetProgram(_programColorBlitI); + } + else if (dst.Info.Format.IsUint()) + { + _pipeline.SetProgram(_programColorBlitU); + } + else + { + _pipeline.SetProgram(_programColorBlitF); + } } int dstWidth = dst.Width; @@ -438,7 +519,7 @@ namespace Ryujinx.Graphics.Metal 0f, 1f); - _pipeline.SetProgram(_programColorBlit); + _pipeline.SetProgram(_programColorBlitF); _pipeline.SetViewports(viewports); _pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip); _pipeline.Draw(4, 1, 0, 0); @@ -502,7 +583,8 @@ namespace Ryujinx.Graphics.Metal ReadOnlySpan clearColor, uint componentMask, int dstWidth, - int dstHeight) + int dstHeight, + Format format) { // Keep original scissor DirtyFlags clearFlags = DirtyFlags.All & (~DirtyFlags.Scissors); @@ -536,7 +618,19 @@ namespace Ryujinx.Graphics.Metal Span componentMasks = stackalloc uint[index + 1]; componentMasks[index] = componentMask; - _pipeline.SetProgram(_programsColorClear[index]); + if (format.IsSint()) + { + _pipeline.SetProgram(_programsColorClearI[index]); + } + else if (format.IsUint()) + { + _pipeline.SetProgram(_programsColorClearU[index]); + } + else + { + _pipeline.SetProgram(_programsColorClearF[index]); + } + _pipeline.SetBlendState(index, new BlendDescriptor()); _pipeline.SetFaceCulling(false, Face.Front); _pipeline.SetDepthTest(new DepthTestDescriptor(false, false, CompareOp.Always)); @@ -630,11 +724,28 @@ namespace Ryujinx.Graphics.Metal public void Dispose() { - _programColorBlit.Dispose(); - foreach (var programColorClear in _programsColorClear) + _programColorBlitF.Dispose(); + _programColorBlitI.Dispose(); + _programColorBlitU.Dispose(); + _programColorBlitMsF.Dispose(); + _programColorBlitMsI.Dispose(); + _programColorBlitMsU.Dispose(); + + foreach (var programColorClear in _programsColorClearF) { programColorClear.Dispose(); } + + foreach (var programColorClear in _programsColorClearU) + { + programColorClear.Dispose(); + } + + foreach (var programColorClear in _programsColorClearI) + { + programColorClear.Dispose(); + } + _programDepthStencilClear.Dispose(); _pipeline.Dispose(); _samplerLinear.Dispose(); diff --git a/src/Ryujinx.Graphics.Metal/Pipeline.cs b/src/Ryujinx.Graphics.Metal/Pipeline.cs index 39f85d2054..15b87fb467 100644 --- a/src/Ryujinx.Graphics.Metal/Pipeline.cs +++ b/src/Ryujinx.Graphics.Metal/Pipeline.cs @@ -269,7 +269,7 @@ namespace Ryujinx.Graphics.Metal return; } - _renderer.HelperShader.ClearColor(index, colors, componentMask, dst.Width, dst.Height); + _renderer.HelperShader.ClearColor(index, colors, componentMask, dst.Width, dst.Height, dst.Info.Format); } public void ClearRenderTargetDepthStencil(int layer, int layerCount, float depthValue, bool depthMask, int stencilValue, int stencilMask) diff --git a/src/Ryujinx.Graphics.Metal/Shaders/Blit.metal b/src/Ryujinx.Graphics.Metal/Shaders/Blit.metal index 7caf0c8463..887878499c 100644 --- a/src/Ryujinx.Graphics.Metal/Shaders/Blit.metal +++ b/src/Ryujinx.Graphics.Metal/Shaders/Blit.metal @@ -17,7 +17,7 @@ struct ConstantBuffers { struct Textures { - texture2d texture; + texture2d texture; sampler sampler; }; @@ -37,7 +37,7 @@ vertex CopyVertexOut vertexMain(uint vid [[vertex_id]], return out; } -fragment float4 fragmentMain(CopyVertexOut in [[stage_in]], +fragment FORMAT4 fragmentMain(CopyVertexOut in [[stage_in]], constant Textures &textures [[buffer(TEXTURES_INDEX)]]) { return textures.texture.sample(textures.sampler, in.uv); } diff --git a/src/Ryujinx.Graphics.Metal/Shaders/BlitMs.metal b/src/Ryujinx.Graphics.Metal/Shaders/BlitMs.metal index 86ee306d37..1077b6ceac 100644 --- a/src/Ryujinx.Graphics.Metal/Shaders/BlitMs.metal +++ b/src/Ryujinx.Graphics.Metal/Shaders/BlitMs.metal @@ -7,12 +7,36 @@ struct CopyVertexOut { float2 uv; }; -struct Textures -{ - texture2d_ms texture; +struct TexCoords { + float data[4]; }; -fragment float4 fragmentMain(CopyVertexOut in [[stage_in]], +struct ConstantBuffers { + constant TexCoords* tex_coord; +}; + +struct Textures +{ + texture2d_ms texture; +}; + +vertex CopyVertexOut vertexMain(uint vid [[vertex_id]], + constant ConstantBuffers &constant_buffers [[buffer(CONSTANT_BUFFERS_INDEX)]]) { + CopyVertexOut out; + + int low = vid & 1; + int high = vid >> 1; + out.uv.x = constant_buffers.tex_coord->data[low]; + out.uv.y = constant_buffers.tex_coord->data[2 + high]; + out.position.x = (float(low) - 0.5f) * 2.0f; + out.position.y = (float(high) - 0.5f) * 2.0f; + out.position.z = 0.0f; + out.position.w = 1.0f; + + return out; +} + +fragment FORMAT4 fragmentMain(CopyVertexOut in [[stage_in]], constant Textures &textures [[buffer(TEXTURES_INDEX)]], uint sample_id [[sample_id]]) { uint2 tex_size = uint2(textures.texture.get_width(), textures.texture.get_height()); diff --git a/src/Ryujinx.Graphics.Metal/Shaders/ColorClear.metal b/src/Ryujinx.Graphics.Metal/Shaders/ColorClear.metal index 306fad87a3..46a57e035d 100644 --- a/src/Ryujinx.Graphics.Metal/Shaders/ColorClear.metal +++ b/src/Ryujinx.Graphics.Metal/Shaders/ColorClear.metal @@ -7,7 +7,7 @@ struct VertexOut { }; struct ClearColor { - float4 data; + FORMAT4 data; }; struct ConstantBuffers { @@ -29,7 +29,7 @@ vertex VertexOut vertexMain(ushort vid [[vertex_id]]) { } struct FragmentOut { - float4 color [[color(COLOR_ATTACHMENT_INDEX)]]; + FORMAT4 color [[color(COLOR_ATTACHMENT_INDEX)]]; }; fragment FragmentOut fragmentMain(VertexOut in [[stage_in]],