2024-08-31 20:42:56 +00:00
|
|
|
using Ryujinx.Common.Configuration;
|
2023-08-02 02:36:07 +00:00
|
|
|
using Ryujinx.Common.Logging;
|
2024-08-31 20:42:56 +00:00
|
|
|
using Ryujinx.Graphics.GAL;
|
|
|
|
using Ryujinx.Graphics.Shader.Translation;
|
2023-07-28 03:36:04 +00:00
|
|
|
using SharpMetal.Foundation;
|
2023-07-28 01:51:20 +00:00
|
|
|
using SharpMetal.Metal;
|
2023-08-02 23:56:59 +00:00
|
|
|
using SharpMetal.QuartzCore;
|
2024-08-31 20:42:56 +00:00
|
|
|
using System;
|
|
|
|
using System.Runtime.CompilerServices;
|
|
|
|
using System.Runtime.Versioning;
|
|
|
|
|
|
|
|
namespace Ryujinx.Graphics.Metal
|
|
|
|
{
|
|
|
|
[SupportedOSPlatform("macos")]
|
|
|
|
public sealed class MetalRenderer : IRenderer
|
|
|
|
{
|
2023-07-28 03:36:04 +00:00
|
|
|
private readonly MTLDevice _device;
|
|
|
|
private readonly MTLCommandQueue _queue;
|
2023-08-02 23:56:59 +00:00
|
|
|
private readonly Func<CAMetalLayer> _getMetalLayer;
|
|
|
|
|
|
|
|
private Pipeline _pipeline;
|
|
|
|
private Window _window;
|
2024-08-31 20:42:56 +00:00
|
|
|
|
|
|
|
public event EventHandler<ScreenCaptureImageInfo> ScreenCaptured;
|
|
|
|
public bool PreferThreading => true;
|
|
|
|
public IPipeline Pipeline => _pipeline;
|
|
|
|
public IWindow Window => _window;
|
|
|
|
|
2023-08-02 23:56:59 +00:00
|
|
|
public MetalRenderer(Func<CAMetalLayer> metalLayer)
|
2024-08-31 20:42:56 +00:00
|
|
|
{
|
2023-07-28 01:51:20 +00:00
|
|
|
_device = MTLDevice.CreateSystemDefaultDevice();
|
2024-03-21 15:35:01 +00:00
|
|
|
|
|
|
|
if (_device.ArgumentBuffersSupport != MTLArgumentBuffersTier.Tier2)
|
|
|
|
{
|
|
|
|
throw new NotSupportedException("Metal backend requires Tier 2 Argument Buffer support.");
|
|
|
|
}
|
|
|
|
|
2023-07-28 03:36:04 +00:00
|
|
|
_queue = _device.NewCommandQueue();
|
2023-08-02 23:56:59 +00:00
|
|
|
_getMetalLayer = metalLayer;
|
2023-07-28 03:36:04 +00:00
|
|
|
}
|
2024-08-31 20:42:56 +00:00
|
|
|
|
2023-07-28 03:36:04 +00:00
|
|
|
public void Initialize(GraphicsDebugLevel logLevel)
|
|
|
|
{
|
2023-08-02 23:56:59 +00:00
|
|
|
var layer = _getMetalLayer();
|
|
|
|
layer.Device = _device;
|
2024-05-19 00:27:27 +00:00
|
|
|
layer.FramebufferOnly = false;
|
2023-08-02 23:56:59 +00:00
|
|
|
|
|
|
|
_window = new Window(this, layer);
|
2023-08-03 12:48:41 +00:00
|
|
|
_pipeline = new Pipeline(_device, _queue);
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void BackgroundContextAction(Action action, bool alwaysBackground = false)
|
|
|
|
{
|
2024-05-21 14:23:42 +00:00
|
|
|
Logger.Warning?.Print(LogClass.Gpu, "Not Implemented!");
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
|
|
|
|
2024-01-14 17:33:59 +00:00
|
|
|
public BufferHandle CreateBuffer(int size, BufferAccess access, BufferHandle storageHint)
|
|
|
|
{
|
2024-01-14 21:50:05 +00:00
|
|
|
return CreateBuffer(size, access);
|
2024-01-14 17:33:59 +00:00
|
|
|
}
|
|
|
|
|
2024-08-31 20:42:56 +00:00
|
|
|
public BufferHandle CreateBuffer(IntPtr pointer, int size)
|
|
|
|
{
|
2023-07-28 01:51:20 +00:00
|
|
|
var buffer = _device.NewBuffer(pointer, (ulong)size, MTLResourceOptions.ResourceStorageModeShared);
|
2024-08-31 20:42:56 +00:00
|
|
|
var bufferPtr = buffer.NativePtr;
|
|
|
|
return Unsafe.As<IntPtr, BufferHandle>(ref bufferPtr);
|
|
|
|
}
|
|
|
|
|
2024-01-14 17:33:59 +00:00
|
|
|
public BufferHandle CreateBufferSparse(ReadOnlySpan<BufferRange> storageBuffers)
|
|
|
|
{
|
|
|
|
throw new NotImplementedException();
|
|
|
|
}
|
|
|
|
|
2024-04-22 21:44:55 +00:00
|
|
|
public IImageArray CreateImageArray(int size, bool isBuffer)
|
|
|
|
{
|
|
|
|
throw new NotImplementedException();
|
|
|
|
}
|
|
|
|
|
2024-08-31 20:42:56 +00:00
|
|
|
public BufferHandle CreateBuffer(int size, BufferAccess access)
|
|
|
|
{
|
2023-07-28 01:51:20 +00:00
|
|
|
var buffer = _device.NewBuffer((ulong)size, MTLResourceOptions.ResourceStorageModeShared);
|
2024-05-23 18:47:05 +00:00
|
|
|
buffer.SetPurgeableState(MTLPurgeableState.NonVolatile);
|
2023-07-28 15:59:07 +00:00
|
|
|
|
2024-08-31 20:42:56 +00:00
|
|
|
var bufferPtr = buffer.NativePtr;
|
|
|
|
return Unsafe.As<IntPtr, BufferHandle>(ref bufferPtr);
|
|
|
|
}
|
|
|
|
|
|
|
|
public IProgram CreateProgram(ShaderSource[] shaders, ShaderInfo info)
|
|
|
|
{
|
2023-10-10 18:14:28 +00:00
|
|
|
return new Program(shaders, _device);
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public ISampler CreateSampler(SamplerCreateInfo info)
|
|
|
|
{
|
2024-03-19 18:05:09 +00:00
|
|
|
return new Sampler(_device, info);
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
|
|
|
|
2023-07-28 01:51:20 +00:00
|
|
|
public ITexture CreateTexture(TextureCreateInfo info)
|
2024-08-31 20:42:56 +00:00
|
|
|
{
|
2023-08-02 23:56:59 +00:00
|
|
|
var texture = new Texture(_device, _pipeline, info);
|
|
|
|
|
|
|
|
return texture;
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
|
|
|
|
2024-04-22 21:44:55 +00:00
|
|
|
public ITextureArray CreateTextureArray(int size, bool isBuffer)
|
|
|
|
{
|
|
|
|
throw new NotImplementedException();
|
|
|
|
}
|
|
|
|
|
2024-08-31 20:42:56 +00:00
|
|
|
public bool PrepareHostMapping(IntPtr address, ulong size)
|
|
|
|
{
|
|
|
|
// TODO: Metal Host Mapping
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void CreateSync(ulong id, bool strict)
|
|
|
|
{
|
2023-08-02 02:36:07 +00:00
|
|
|
Logger.Warning?.Print(LogClass.Gpu, "Not Implemented!");
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void DeleteBuffer(BufferHandle buffer)
|
|
|
|
{
|
2023-07-28 15:55:52 +00:00
|
|
|
MTLBuffer mtlBuffer = new(Unsafe.As<BufferHandle, IntPtr>(ref buffer));
|
|
|
|
mtlBuffer.SetPurgeableState(MTLPurgeableState.Empty);
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
|
|
|
|
2023-07-28 15:55:52 +00:00
|
|
|
public unsafe PinnedSpan<byte> GetBufferData(BufferHandle buffer, int offset, int size)
|
2024-08-31 20:42:56 +00:00
|
|
|
{
|
2023-07-28 15:55:52 +00:00
|
|
|
MTLBuffer mtlBuffer = new(Unsafe.As<BufferHandle, IntPtr>(ref buffer));
|
|
|
|
return new PinnedSpan<byte>(IntPtr.Add(mtlBuffer.Contents, offset).ToPointer(), size);
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public Capabilities GetCapabilities()
|
|
|
|
{
|
|
|
|
// TODO: Finalize these values
|
|
|
|
return new Capabilities(
|
|
|
|
api: TargetApi.Metal,
|
|
|
|
vendorName: HardwareInfoTools.GetVendor(),
|
2024-05-23 18:47:05 +00:00
|
|
|
SystemMemoryType.UnifiedMemory,
|
2024-08-31 20:42:56 +00:00
|
|
|
hasFrontFacingBug: false,
|
|
|
|
hasVectorIndexingBug: true,
|
|
|
|
needsFragmentOutputSpecialization: true,
|
|
|
|
reduceShaderPrecision: true,
|
|
|
|
supportsAstcCompression: true,
|
|
|
|
supportsBc123Compression: true,
|
|
|
|
supportsBc45Compression: true,
|
|
|
|
supportsBc67Compression: true,
|
|
|
|
supportsEtc2Compression: true,
|
|
|
|
supports3DTextureCompression: true,
|
|
|
|
supportsBgraFormat: true,
|
|
|
|
supportsR4G4Format: false,
|
|
|
|
supportsR4G4B4A4Format: true,
|
2024-05-15 13:03:53 +00:00
|
|
|
supportsScaledVertexFormats: true,
|
2024-08-31 20:42:56 +00:00
|
|
|
supportsSnormBufferTextureFormat: true,
|
2024-01-14 17:33:59 +00:00
|
|
|
supportsSparseBuffer: false,
|
2024-08-31 20:42:56 +00:00
|
|
|
supports5BitComponentFormat: true,
|
|
|
|
supportsBlendEquationAdvanced: false,
|
|
|
|
supportsFragmentShaderInterlock: true,
|
|
|
|
supportsFragmentShaderOrderingIntel: false,
|
|
|
|
supportsGeometryShader: false,
|
|
|
|
supportsGeometryShaderPassthrough: false,
|
2023-07-28 01:51:20 +00:00
|
|
|
supportsTransformFeedback: false,
|
2024-08-31 20:42:56 +00:00
|
|
|
supportsImageLoadFormatted: false,
|
|
|
|
supportsLayerVertexTessellation: false,
|
|
|
|
supportsMismatchingViewFormat: true,
|
|
|
|
supportsCubemapView: true,
|
|
|
|
supportsNonConstantTextureOffset: false,
|
2024-05-15 13:03:53 +00:00
|
|
|
supportsQuads: false,
|
2024-04-22 21:44:55 +00:00
|
|
|
// TODO: Metal Bindless Support
|
|
|
|
supportsSeparateSampler: false,
|
2024-08-31 20:42:56 +00:00
|
|
|
supportsShaderBallot: false,
|
2023-07-28 01:51:20 +00:00
|
|
|
supportsShaderBarrierDivergence: false,
|
|
|
|
supportsShaderFloat64: false,
|
2024-01-14 17:33:59 +00:00
|
|
|
supportsTextureGatherOffsets: false,
|
2024-08-31 20:42:56 +00:00
|
|
|
supportsTextureShadowLod: false,
|
2023-08-30 18:35:57 +00:00
|
|
|
supportsVertexStoreAndAtomics: false,
|
2024-08-31 20:42:56 +00:00
|
|
|
supportsViewportIndexVertexTessellation: false,
|
|
|
|
supportsViewportMask: false,
|
|
|
|
supportsViewportSwizzle: false,
|
|
|
|
supportsIndirectParameters: true,
|
2023-07-28 01:51:20 +00:00
|
|
|
supportsDepthClipControl: false,
|
2024-08-31 20:42:56 +00:00
|
|
|
maximumUniformBuffersPerStage: Constants.MaxUniformBuffersPerStage,
|
|
|
|
maximumStorageBuffersPerStage: Constants.MaxStorageBuffersPerStage,
|
|
|
|
maximumTexturesPerStage: Constants.MaxTexturesPerStage,
|
|
|
|
maximumImagesPerStage: Constants.MaxTextureBindings,
|
|
|
|
maximumComputeSharedMemorySize: (int)_device.MaxThreadgroupMemoryLength,
|
|
|
|
maximumSupportedAnisotropy: 0,
|
2023-08-30 18:35:57 +00:00
|
|
|
shaderSubgroupSize: 256,
|
2024-08-31 20:42:56 +00:00
|
|
|
storageBufferOffsetAlignment: 0,
|
2023-08-30 18:35:57 +00:00
|
|
|
textureBufferOffsetAlignment: 0,
|
2024-08-31 20:42:56 +00:00
|
|
|
gatherBiasPrecision: 0
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public ulong GetCurrentSync()
|
|
|
|
{
|
2023-08-02 02:36:07 +00:00
|
|
|
Logger.Warning?.Print(LogClass.Gpu, "Not Implemented!");
|
|
|
|
return 0;
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public HardwareInfo GetHardwareInfo()
|
|
|
|
{
|
2024-01-27 21:08:57 +00:00
|
|
|
return new HardwareInfo(HardwareInfoTools.GetVendor(), HardwareInfoTools.GetModel(), "Apple");
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info)
|
|
|
|
{
|
|
|
|
throw new NotImplementedException();
|
|
|
|
}
|
|
|
|
|
2023-07-28 03:36:04 +00:00
|
|
|
public unsafe void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan<byte> data)
|
2024-08-31 20:42:56 +00:00
|
|
|
{
|
2024-05-22 21:21:44 +00:00
|
|
|
var blitEncoder = _pipeline.GetOrCreateBlitEncoder();
|
|
|
|
|
2024-05-23 17:15:23 +00:00
|
|
|
using MTLBuffer src = _device.NewBuffer((ulong)data.Length, MTLResourceOptions.ResourceStorageModeManaged);
|
2023-07-28 03:36:04 +00:00
|
|
|
{
|
2024-05-23 17:15:23 +00:00
|
|
|
var span = new Span<byte>(src.Contents.ToPointer(), data.Length);
|
|
|
|
data.CopyTo(span);
|
|
|
|
src.DidModifyRange(new NSRange
|
|
|
|
{
|
|
|
|
location = 0,
|
|
|
|
length = (ulong)data.Length
|
|
|
|
});
|
|
|
|
|
|
|
|
MTLBuffer dst = new(Unsafe.As<BufferHandle, IntPtr>(ref buffer));
|
|
|
|
blitEncoder.CopyFromBuffer(src, 0, dst, (ulong)offset, (ulong)data.Length);
|
|
|
|
}
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void UpdateCounters()
|
|
|
|
{
|
2023-07-28 03:36:04 +00:00
|
|
|
// https://developer.apple.com/documentation/metal/gpu_counters_and_counter_sample_buffers/creating_a_counter_sample_buffer_to_store_a_gpu_s_counter_data_during_a_pass?language=objc
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void PreFrame()
|
|
|
|
{
|
2023-07-28 03:36:04 +00:00
|
|
|
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
|
|
|
|
2023-07-28 01:51:20 +00:00
|
|
|
public ICounterEvent ReportCounter(CounterType type, EventHandler<ulong> resultHandler, float divisor, bool hostReserved)
|
2024-08-31 20:42:56 +00:00
|
|
|
{
|
2023-07-28 03:36:04 +00:00
|
|
|
// https://developer.apple.com/documentation/metal/gpu_counters_and_counter_sample_buffers/creating_a_counter_sample_buffer_to_store_a_gpu_s_counter_data_during_a_pass?language=objc
|
2023-07-28 17:29:26 +00:00
|
|
|
var counterEvent = new CounterEvent();
|
|
|
|
resultHandler?.Invoke(counterEvent, type == CounterType.SamplesPassed ? (ulong)1 : 0);
|
|
|
|
return counterEvent;
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void ResetCounter(CounterType type)
|
|
|
|
{
|
2023-07-28 03:36:04 +00:00
|
|
|
// https://developer.apple.com/documentation/metal/gpu_counters_and_counter_sample_buffers/creating_a_counter_sample_buffer_to_store_a_gpu_s_counter_data_during_a_pass?language=objc
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void WaitSync(ulong id)
|
|
|
|
{
|
|
|
|
throw new NotImplementedException();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void SetInterruptAction(Action<Action> interruptAction)
|
|
|
|
{
|
|
|
|
// Not needed for now
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Screenshot()
|
|
|
|
{
|
|
|
|
// TODO: Screenshots
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
{
|
|
|
|
_pipeline.Dispose();
|
2024-03-20 18:35:35 +00:00
|
|
|
_window.Dispose();
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
|
|
|
}
|
2023-07-28 01:51:20 +00:00
|
|
|
}
|