2024-05-18 18:54:55 -04:00
|
|
|
using Ryujinx.Common;
|
|
|
|
using Ryujinx.Graphics.GAL;
|
|
|
|
using Ryujinx.Graphics.Shader;
|
|
|
|
using Ryujinx.Graphics.Shader.Translation;
|
2024-05-22 17:21:44 -04:00
|
|
|
using SharpMetal.Foundation;
|
2024-05-18 18:54:55 -04:00
|
|
|
using SharpMetal.Metal;
|
|
|
|
using System;
|
2024-05-24 09:28:16 -04:00
|
|
|
using System.Collections.Generic;
|
2024-05-22 17:21:44 -04:00
|
|
|
using System.Runtime.CompilerServices;
|
2024-05-18 18:54:55 -04:00
|
|
|
using System.Runtime.Versioning;
|
|
|
|
|
|
|
|
namespace Ryujinx.Graphics.Metal
|
|
|
|
{
|
|
|
|
[SupportedOSPlatform("macos")]
|
|
|
|
class HelperShader : IDisposable
|
|
|
|
{
|
|
|
|
private const string ShadersSourcePath = "/Ryujinx.Graphics.Metal/Shaders";
|
2024-05-18 20:40:37 -04:00
|
|
|
private readonly Pipeline _pipeline;
|
2024-05-18 18:54:55 -04:00
|
|
|
private MTLDevice _device;
|
|
|
|
|
|
|
|
private readonly IProgram _programColorBlit;
|
2024-05-24 09:28:16 -04:00
|
|
|
private readonly List<IProgram> _programsColorClear = new();
|
2024-05-18 18:54:55 -04:00
|
|
|
private readonly IProgram _programDepthStencilClear;
|
|
|
|
|
|
|
|
public HelperShader(MTLDevice device, Pipeline pipeline)
|
|
|
|
{
|
|
|
|
_device = device;
|
|
|
|
_pipeline = pipeline;
|
|
|
|
|
|
|
|
var blitSource = ReadMsl("Blit.metal");
|
|
|
|
_programColorBlit = new Program(
|
|
|
|
[
|
|
|
|
new ShaderSource(blitSource, ShaderStage.Fragment, TargetLanguage.Msl),
|
|
|
|
new ShaderSource(blitSource, ShaderStage.Vertex, TargetLanguage.Msl)
|
|
|
|
], device);
|
|
|
|
|
2024-05-22 17:21:44 -04:00
|
|
|
var colorClearSource = ReadMsl("ColorClear.metal");
|
2024-05-24 09:28:16 -04:00
|
|
|
for (int i = 0; i < Constants.MaxColorAttachments; i++)
|
|
|
|
{
|
|
|
|
var crntSource = colorClearSource.Replace("COLOR_ATTACHMENT_INDEX", i.ToString());
|
|
|
|
_programsColorClear.Add(new Program(
|
|
|
|
[
|
|
|
|
new ShaderSource(crntSource, ShaderStage.Fragment, TargetLanguage.Msl),
|
|
|
|
new ShaderSource(crntSource, ShaderStage.Vertex, TargetLanguage.Msl)
|
|
|
|
], device));
|
|
|
|
}
|
2024-05-22 17:21:44 -04:00
|
|
|
|
2024-05-22 20:26:54 -04:00
|
|
|
var depthStencilClearSource = ReadMsl("DepthStencilClear.metal");
|
|
|
|
_programDepthStencilClear = new Program(
|
|
|
|
[
|
|
|
|
new ShaderSource(depthStencilClearSource, ShaderStage.Fragment, TargetLanguage.Msl),
|
|
|
|
new ShaderSource(depthStencilClearSource, ShaderStage.Vertex, TargetLanguage.Msl)
|
|
|
|
], device);
|
2024-05-18 18:54:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
private static string ReadMsl(string fileName)
|
|
|
|
{
|
|
|
|
return EmbeddedResources.ReadAllText(string.Join('/', ShadersSourcePath, fileName));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void BlitColor(
|
|
|
|
ITexture source,
|
|
|
|
ITexture destination)
|
|
|
|
{
|
|
|
|
var sampler = _device.NewSamplerState(new MTLSamplerDescriptor
|
|
|
|
{
|
|
|
|
MinFilter = MTLSamplerMinMagFilter.Nearest,
|
|
|
|
MagFilter = MTLSamplerMinMagFilter.Nearest,
|
|
|
|
MipFilter = MTLSamplerMipFilter.NotMipmapped
|
|
|
|
});
|
|
|
|
|
2024-05-24 09:09:06 -04:00
|
|
|
// Save current state
|
|
|
|
_pipeline.SaveState();
|
|
|
|
|
2024-05-18 18:54:55 -04:00
|
|
|
_pipeline.SetProgram(_programColorBlit);
|
2024-05-24 12:37:31 -04:00
|
|
|
// Viewport and scissor needs to be set before render pass begin so as not to bind the old ones
|
2024-05-25 02:39:45 -04:00
|
|
|
_pipeline.SetViewports([]);
|
|
|
|
_pipeline.SetScissors([]);
|
2024-05-18 18:54:55 -04:00
|
|
|
_pipeline.SetRenderTargets([destination], null);
|
|
|
|
_pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, source, new Sampler(sampler));
|
|
|
|
_pipeline.SetPrimitiveTopology(PrimitiveTopology.Triangles);
|
|
|
|
_pipeline.Draw(6, 1, 0, 0);
|
2024-05-24 09:09:06 -04:00
|
|
|
|
|
|
|
// Restore previous state
|
|
|
|
_pipeline.RestoreState();
|
2024-05-18 18:54:55 -04:00
|
|
|
}
|
|
|
|
|
2024-05-22 17:21:44 -04:00
|
|
|
public unsafe void ClearColor(
|
2024-05-24 09:28:16 -04:00
|
|
|
int index,
|
2024-05-22 17:21:44 -04:00
|
|
|
ReadOnlySpan<float> clearColor)
|
2024-05-18 18:54:55 -04:00
|
|
|
{
|
2024-05-22 17:21:44 -04:00
|
|
|
const int ClearColorBufferSize = 16;
|
2024-05-18 18:54:55 -04:00
|
|
|
|
2024-05-22 17:21:44 -04:00
|
|
|
var buffer = _device.NewBuffer(ClearColorBufferSize, MTLResourceOptions.ResourceStorageModeManaged);
|
|
|
|
var span = new Span<float>(buffer.Contents.ToPointer(), ClearColorBufferSize);
|
|
|
|
clearColor.CopyTo(span);
|
2024-05-18 18:54:55 -04:00
|
|
|
|
2024-05-22 17:21:44 -04:00
|
|
|
buffer.DidModifyRange(new NSRange
|
2024-05-18 18:54:55 -04:00
|
|
|
{
|
2024-05-22 17:21:44 -04:00
|
|
|
location = 0,
|
|
|
|
length = ClearColorBufferSize
|
|
|
|
});
|
2024-05-18 18:54:55 -04:00
|
|
|
|
2024-05-22 17:21:44 -04:00
|
|
|
var handle = buffer.NativePtr;
|
|
|
|
var range = new BufferRange(Unsafe.As<IntPtr, BufferHandle>(ref handle), 0, ClearColorBufferSize);
|
|
|
|
|
2024-05-24 09:09:06 -04:00
|
|
|
// Save current state
|
|
|
|
_pipeline.SaveState();
|
|
|
|
|
2024-05-22 17:21:44 -04:00
|
|
|
_pipeline.SetUniformBuffers([new BufferAssignment(0, range)]);
|
|
|
|
|
2024-05-24 09:28:16 -04:00
|
|
|
_pipeline.SetProgram(_programsColorClear[index]);
|
2024-05-22 17:21:44 -04:00
|
|
|
// _pipeline.SetRenderTargetColorMasks([componentMask]);
|
2024-05-18 18:54:55 -04:00
|
|
|
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
|
|
|
_pipeline.Draw(4, 1, 0, 0);
|
2024-05-24 09:09:06 -04:00
|
|
|
|
|
|
|
// Restore previous state
|
|
|
|
_pipeline.RestoreState();
|
2024-05-18 18:54:55 -04:00
|
|
|
}
|
|
|
|
|
2024-05-22 20:26:54 -04:00
|
|
|
public unsafe void ClearDepthStencil(
|
|
|
|
ReadOnlySpan<float> depthValue,
|
2024-05-18 18:54:55 -04:00
|
|
|
bool depthMask,
|
|
|
|
int stencilValue,
|
2024-05-22 20:26:54 -04:00
|
|
|
int stencilMask)
|
2024-05-18 18:54:55 -04:00
|
|
|
{
|
2024-05-22 20:26:54 -04:00
|
|
|
const int ClearColorBufferSize = 16;
|
|
|
|
|
|
|
|
var buffer = _device.NewBuffer(ClearColorBufferSize, MTLResourceOptions.ResourceStorageModeManaged);
|
|
|
|
var span = new Span<float>(buffer.Contents.ToPointer(), ClearColorBufferSize);
|
|
|
|
depthValue.CopyTo(span);
|
|
|
|
|
|
|
|
buffer.DidModifyRange(new NSRange
|
|
|
|
{
|
|
|
|
location = 0,
|
|
|
|
length = ClearColorBufferSize
|
|
|
|
});
|
2024-05-18 18:54:55 -04:00
|
|
|
|
2024-05-22 20:26:54 -04:00
|
|
|
var handle = buffer.NativePtr;
|
|
|
|
var range = new BufferRange(Unsafe.As<IntPtr, BufferHandle>(ref handle), 0, ClearColorBufferSize);
|
|
|
|
|
2024-05-24 09:09:06 -04:00
|
|
|
// Save current state
|
|
|
|
_pipeline.SaveState();
|
|
|
|
|
2024-05-22 20:26:54 -04:00
|
|
|
_pipeline.SetUniformBuffers([new BufferAssignment(0, range)]);
|
2024-05-18 18:54:55 -04:00
|
|
|
|
|
|
|
_pipeline.SetProgram(_programDepthStencilClear);
|
|
|
|
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
|
|
|
_pipeline.SetDepthTest(new DepthTestDescriptor(true, depthMask, CompareOp.Always));
|
2024-05-22 20:26:54 -04:00
|
|
|
// _pipeline.SetStencilTest(CreateStencilTestDescriptor(stencilMask != 0, stencilValue, 0xFF, stencilMask));
|
2024-05-18 18:54:55 -04:00
|
|
|
_pipeline.Draw(4, 1, 0, 0);
|
2024-05-24 09:09:06 -04:00
|
|
|
|
|
|
|
// Restore previous state
|
|
|
|
_pipeline.RestoreState();
|
2024-05-18 18:54:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
private static StencilTestDescriptor CreateStencilTestDescriptor(
|
|
|
|
bool enabled,
|
|
|
|
int refValue = 0,
|
|
|
|
int compareMask = 0xff,
|
|
|
|
int writeMask = 0xff)
|
|
|
|
{
|
|
|
|
return new StencilTestDescriptor(
|
|
|
|
enabled,
|
|
|
|
CompareOp.Always,
|
|
|
|
StencilOp.Replace,
|
|
|
|
StencilOp.Replace,
|
|
|
|
StencilOp.Replace,
|
|
|
|
refValue,
|
|
|
|
compareMask,
|
|
|
|
writeMask,
|
|
|
|
CompareOp.Always,
|
|
|
|
StencilOp.Replace,
|
|
|
|
StencilOp.Replace,
|
|
|
|
StencilOp.Replace,
|
|
|
|
refValue,
|
|
|
|
compareMask,
|
|
|
|
writeMask);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
{
|
|
|
|
_programColorBlit.Dispose();
|
2024-05-24 09:28:16 -04:00
|
|
|
foreach (var programColorClear in _programsColorClear)
|
|
|
|
{
|
|
|
|
programColorClear.Dispose();
|
|
|
|
}
|
2024-05-18 18:54:55 -04:00
|
|
|
_programDepthStencilClear.Dispose();
|
|
|
|
_pipeline.Dispose();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|