Seizure my beloved is working

This commit is contained in:
Isaac Marovitz 2023-08-02 19:56:59 -04:00 committed by Isaac Marovitz
parent 6d722d83ba
commit aaa140e510
5 changed files with 109 additions and 39 deletions

View file

@ -4,6 +4,7 @@ using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Shader.Translation; using Ryujinx.Graphics.Shader.Translation;
using SharpMetal.Foundation; using SharpMetal.Foundation;
using SharpMetal.Metal; using SharpMetal.Metal;
using SharpMetal.QuartzCore;
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.Versioning; using System.Runtime.Versioning;
@ -14,25 +15,43 @@ namespace Ryujinx.Graphics.Metal
public sealed class MetalRenderer : IRenderer public sealed class MetalRenderer : IRenderer
{ {
private readonly MTLDevice _device; private readonly MTLDevice _device;
private readonly Window _window;
private readonly Pipeline _pipeline;
private readonly MTLCommandQueue _queue; private readonly MTLCommandQueue _queue;
private readonly Func<CAMetalLayer> _getMetalLayer;
private Pipeline _pipeline;
private Window _window;
public event EventHandler<ScreenCaptureImageInfo> ScreenCaptured; public event EventHandler<ScreenCaptureImageInfo> ScreenCaptured;
public bool PreferThreading => true; public bool PreferThreading => true;
public IPipeline Pipeline => _pipeline; public IPipeline Pipeline => _pipeline;
public IWindow Window => _window; public IWindow Window => _window;
public MetalRenderer() public MetalRenderer(Func<CAMetalLayer> metalLayer)
{ {
_device = MTLDevice.CreateSystemDefaultDevice(); _device = MTLDevice.CreateSystemDefaultDevice();
_queue = _device.NewCommandQueue(); _queue = _device.NewCommandQueue();
_pipeline = new Pipeline(_device, _queue); _getMetalLayer = metalLayer;
_window = new Window(this);
} }
public void Initialize(GraphicsDebugLevel logLevel) public void Initialize(GraphicsDebugLevel logLevel)
{ {
var layer = _getMetalLayer();
layer.Device = _device;
var captureDescriptor = new MTLCaptureDescriptor();
captureDescriptor.CaptureObject = _queue;
captureDescriptor.Destination = MTLCaptureDestination.GPUTraceDocument;
captureDescriptor.OutputURL = NSURL.FileURLWithPath(StringHelper.NSString("/Users/isaacmarovitz/Desktop/Trace.gputrace"));
var captureError = new NSError(IntPtr.Zero);
MTLCaptureManager.SharedCaptureManager().StartCapture(captureDescriptor, ref captureError);
if (captureError != IntPtr.Zero)
{
Console.Write($"Failed to start capture! {StringHelper.String(captureError.LocalizedDescription)}");
}
_window = new Window(this, layer);
_pipeline = new Pipeline(_device, _queue, layer);
} }
public void BackgroundContextAction(Action action, bool alwaysBackground = false) public void BackgroundContextAction(Action action, bool alwaysBackground = false)
@ -96,7 +115,10 @@ namespace Ryujinx.Graphics.Metal
public ITexture CreateTexture(TextureCreateInfo info) public ITexture CreateTexture(TextureCreateInfo info)
{ {
return new Texture(_device, _pipeline, info); var texture = new Texture(_device, _pipeline, info);
Logger.Warning?.Print(LogClass.Gpu, "Texture created!");
return texture;
} }
public bool PrepareHostMapping(IntPtr address, ulong size) public bool PrepareHostMapping(IntPtr address, ulong size)

View file

@ -4,6 +4,7 @@ using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Shader; using Ryujinx.Graphics.Shader;
using SharpMetal.Foundation; using SharpMetal.Foundation;
using SharpMetal.Metal; using SharpMetal.Metal;
using SharpMetal.QuartzCore;
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.Versioning; using System.Runtime.Versioning;
@ -28,8 +29,10 @@ namespace Ryujinx.Graphics.Metal
private MTLBuffer _indexBuffer; private MTLBuffer _indexBuffer;
private MTLIndexType _indexType; private MTLIndexType _indexType;
private ulong _indexBufferOffset; private ulong _indexBufferOffset;
private MTLClearColor _clearColor = new() { alpha = 1.0f };
private int frameCount = 0;
public Pipeline(MTLDevice device, MTLCommandQueue commandQueue) public Pipeline(MTLDevice device, MTLCommandQueue commandQueue, CAMetalLayer metalLayer)
{ {
_device = device; _device = device;
_mtlCommandQueue = commandQueue; _mtlCommandQueue = commandQueue;
@ -49,13 +52,17 @@ namespace Ryujinx.Graphics.Metal
// TODO: Recreate descriptor and encoder state as needed // TODO: Recreate descriptor and encoder state as needed
var renderPipelineDescriptor = new MTLRenderPipelineDescriptor(); var renderPipelineDescriptor = new MTLRenderPipelineDescriptor();
renderPipelineDescriptor.VertexFunction = vertexFunction; renderPipelineDescriptor.VertexFunction = vertexFunction;
renderPipelineDescriptor.FragmentFunction = fragmentFunction; // renderPipelineDescriptor.FragmentFunction = fragmentFunction;
// TODO: This should not be hardcoded, but a bug in SharpMetal prevents me from doing this correctly
renderPipelineDescriptor.ColorAttachments.Object(0).PixelFormat = MTLPixelFormat.BGRA8Unorm;
_renderEncoderState = new(_device.NewRenderPipelineState(renderPipelineDescriptor, ref error), _device); var renderPipelineState = _device.NewRenderPipelineState(renderPipelineDescriptor, ref error);
if (error != IntPtr.Zero) if (error != IntPtr.Zero)
{ {
Logger.Error?.PrintMsg(LogClass.Gpu, $"Failed to create Render Pipeline State: {StringHelper.String(error.LocalizedDescription)}"); Logger.Error?.PrintMsg(LogClass.Gpu, $"Failed to create Render Pipeline State: {StringHelper.String(error.LocalizedDescription)}");
} }
_renderEncoderState = new RenderEncoderState(renderPipelineState, _device);
// //
_commandBuffer = _mtlCommandQueue.CommandBuffer(); _commandBuffer = _mtlCommandQueue.CommandBuffer();
@ -68,6 +75,7 @@ namespace Ryujinx.Graphics.Metal
_currentEncoder.EndEncoding(); _currentEncoder.EndEncoding();
_currentEncoder = null; _currentEncoder = null;
} }
Logger.Warning?.Print(LogClass.Gpu, "Current pass ended");
} }
public MTLRenderCommandEncoder BeginRenderPass() public MTLRenderCommandEncoder BeginRenderPass()
@ -77,6 +85,7 @@ namespace Ryujinx.Graphics.Metal
var descriptor = new MTLRenderPassDescriptor(); var descriptor = new MTLRenderPassDescriptor();
var renderCommandEncoder = _commandBuffer.RenderCommandEncoder(descriptor); var renderCommandEncoder = _commandBuffer.RenderCommandEncoder(descriptor);
_renderEncoderState.SetEncoderState(renderCommandEncoder); _renderEncoderState.SetEncoderState(renderCommandEncoder);
Logger.Warning?.Print(LogClass.Gpu, "Began render pass");
_currentEncoder = renderCommandEncoder; _currentEncoder = renderCommandEncoder;
return renderCommandEncoder; return renderCommandEncoder;
@ -88,6 +97,7 @@ namespace Ryujinx.Graphics.Metal
var descriptor = new MTLBlitPassDescriptor(); var descriptor = new MTLBlitPassDescriptor();
var blitCommandEncoder = _commandBuffer.BlitCommandEncoder(descriptor); var blitCommandEncoder = _commandBuffer.BlitCommandEncoder(descriptor);
Logger.Warning?.Print(LogClass.Gpu, "Began blit pass");
_currentEncoder = blitCommandEncoder; _currentEncoder = blitCommandEncoder;
return blitCommandEncoder; return blitCommandEncoder;
@ -99,18 +109,43 @@ namespace Ryujinx.Graphics.Metal
var descriptor = new MTLComputePassDescriptor(); var descriptor = new MTLComputePassDescriptor();
var computeCommandEncoder = _commandBuffer.ComputeCommandEncoder(descriptor); var computeCommandEncoder = _commandBuffer.ComputeCommandEncoder(descriptor);
Logger.Warning?.Print(LogClass.Gpu, "Began compute pass");
_currentEncoder = computeCommandEncoder; _currentEncoder = computeCommandEncoder;
return computeCommandEncoder; return computeCommandEncoder;
} }
public void Present() public void Present(CAMetalDrawable drawable)
{ {
EndCurrentPass(); EndCurrentPass();
// TODO: Give command buffer a valid MTLDrawable var descriptor = new MTLRenderPassDescriptor();
// _commandBuffer.PresentDrawable(); descriptor.ColorAttachments.Object(0).Texture = drawable.Texture;
// _commandBuffer.Commit(); descriptor.ColorAttachments.Object(0).LoadAction = MTLLoadAction.Clear;
descriptor.ColorAttachments.Object(0).ClearColor = _clearColor;
var renderCommandEncoder = _commandBuffer.RenderCommandEncoder(descriptor);
Logger.Warning?.Print(LogClass.Gpu, "Began present");
_renderEncoderState.SetEncoderState(renderCommandEncoder);
// Barry goes here
// renderCommandEncoder.SetFragmentTexture(_renderTarget, 0);
renderCommandEncoder.DrawPrimitives(MTLPrimitiveType.Triangle, 0, 6);
renderCommandEncoder.EndEncoding();
_commandBuffer.PresentDrawable(drawable);
_commandBuffer.Commit();
Logger.Warning?.Print(LogClass.Gpu, "Presented");
frameCount++;
if (frameCount >= 5)
{
MTLCaptureManager.SharedCaptureManager().StopCapture();
Logger.Warning?.Print(LogClass.Gpu, "Trace ended!");
}
_commandBuffer = _mtlCommandQueue.CommandBuffer(); _commandBuffer = _mtlCommandQueue.CommandBuffer();
} }
@ -147,7 +182,7 @@ namespace Ryujinx.Graphics.Metal
public void ClearRenderTargetColor(int index, int layer, int layerCount, uint componentMask, ColorF color) public void ClearRenderTargetColor(int index, int layer, int layerCount, uint componentMask, ColorF color)
{ {
Logger.Warning?.Print(LogClass.Gpu, "Not Implemented!"); _clearColor = new MTLClearColor { red = color.Red, green = color.Green, blue = color.Blue, alpha = color.Alpha};
} }
public void ClearRenderTargetDepthStencil(int layer, int layerCount, float depthValue, bool depthMask, int stencilValue, public void ClearRenderTargetDepthStencil(int layer, int layerCount, float depthValue, bool depthMask, int stencilValue,

View file

@ -17,23 +17,23 @@ namespace Ryujinx.Graphics.Metal
private MTLStencilDescriptor _backFaceStencil = null; private MTLStencilDescriptor _backFaceStencil = null;
private MTLStencilDescriptor _frontFaceStencil = null; private MTLStencilDescriptor _frontFaceStencil = null;
public MTLRenderPipelineState RenderPipelineState; public MTLRenderPipelineState CopyPipeline;
public PrimitiveTopology Topology = PrimitiveTopology.Triangles; public PrimitiveTopology Topology = PrimitiveTopology.Triangles;
public MTLCullMode CullMode = MTLCullMode.None; public MTLCullMode CullMode = MTLCullMode.None;
public MTLWinding Winding = MTLWinding.Clockwise; public MTLWinding Winding = MTLWinding.Clockwise;
public RenderEncoderState(MTLRenderPipelineState renderPipelineState, MTLDevice device) public RenderEncoderState(MTLRenderPipelineState copyPipeline, MTLDevice device)
{ {
_device = device; _device = device;
RenderPipelineState = renderPipelineState; CopyPipeline = copyPipeline;
} }
public void SetEncoderState(MTLRenderCommandEncoder renderCommandEncoder) public void SetEncoderState(MTLRenderCommandEncoder renderCommandEncoder)
{ {
renderCommandEncoder.SetRenderPipelineState(RenderPipelineState); renderCommandEncoder.SetRenderPipelineState(CopyPipeline);
renderCommandEncoder.SetCullMode(CullMode); renderCommandEncoder.SetCullMode(CullMode);
renderCommandEncoder.SetFrontFacingWinding(Winding); renderCommandEncoder.SetFrontFacingWinding(Winding);
renderCommandEncoder.SetDepthStencilState(_depthStencilState); // renderCommandEncoder.SetDepthStencilState(_depthStencilState);
} }
public MTLDepthStencilState UpdateStencilState(MTLStencilDescriptor backFace, MTLStencilDescriptor frontFace) public MTLDepthStencilState UpdateStencilState(MTLStencilDescriptor backFace, MTLStencilDescriptor frontFace)

View file

@ -2,29 +2,35 @@
using namespace metal; using namespace metal;
struct TexCoordIn { constant float2 quadVertices[] = {
float4 tex_coord_in_data; float2(-1, -1),
float2(-1, 1),
float2( 1, 1),
float2(-1, -1),
float2( 1, 1),
float2( 1, -1)
}; };
vertex float4 vertexMain(uint vertexID [[vertex_id]], struct CopyVertexOut {
constant TexCoordIn& tex_coord_in [[buffer(1)]]) { float4 position [[position]];
int low = vertexID & 1; float2 uv;
int high = vertexID >> 1; };
float2 tex_coord;
tex_coord.x = tex_coord_in.tex_coord_in_data[low];
tex_coord.y = tex_coord_in.tex_coord_in_data[2 + high];
float4 position; vertex CopyVertexOut vertexMain(unsigned short vid [[vertex_id]]) {
position.x = (float(low) - 0.5) * 2.0; float2 position = quadVertices[vid];
position.y = (float(high) - 0.5) * 2.0;
position.z = 0.0;
position.w = 1.0;
return position; CopyVertexOut out;
out.position = float4(position, 0, 1);
out.uv = position * 0.5f + 0.5f;
return out;
} }
fragment float4 fragmentMain(float2 tex_coord [[stage_in]], fragment float4 fragmentMain(CopyVertexOut in [[stage_in]],
texture2d<float> tex [[texture(0)]]) { texture2d<float> tex) {
float4 color = tex.sample(metal::address::clamp_to_edge, tex_coord); constexpr sampler sam(min_filter::nearest, mag_filter::nearest, mip_filter::none);
return color;
float3 color = tex.sample(sam, in.uv).xyz;
return float4(color, 1.0f);
} }

View file

@ -9,7 +9,7 @@ using System.Runtime.Versioning;
namespace Ryujinx.Graphics.Metal namespace Ryujinx.Graphics.Metal
{ {
[SupportedOSPlatform("macos")] [SupportedOSPlatform("macos")]
class Texture : ITexture, IDisposable public class Texture : ITexture, IDisposable
{ {
private readonly TextureCreateInfo _info; private readonly TextureCreateInfo _info;
private readonly Pipeline _pipeline; private readonly Pipeline _pipeline;
@ -23,6 +23,7 @@ namespace Ryujinx.Graphics.Metal
public Texture(MTLDevice device, Pipeline pipeline, TextureCreateInfo info) public Texture(MTLDevice device, Pipeline pipeline, TextureCreateInfo info)
{ {
Logger.Warning?.Print(LogClass.Gpu, "Texture init");
_device = device; _device = device;
_pipeline = pipeline; _pipeline = pipeline;
_info = info; _info = info;
@ -50,6 +51,7 @@ namespace Ryujinx.Graphics.Metal
public void CopyTo(ITexture destination, int firstLayer, int firstLevel) public void CopyTo(ITexture destination, int firstLayer, int firstLevel)
{ {
Logger.Warning?.Print(LogClass.Gpu, "Copy to");
MTLBlitCommandEncoder blitCommandEncoder; MTLBlitCommandEncoder blitCommandEncoder;
if (_pipeline.CurrentEncoder is MTLBlitCommandEncoder encoder) if (_pipeline.CurrentEncoder is MTLBlitCommandEncoder encoder)
@ -77,6 +79,7 @@ namespace Ryujinx.Graphics.Metal
public void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel) public void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel)
{ {
Logger.Warning?.Print(LogClass.Gpu, "Copy to");
MTLBlitCommandEncoder blitCommandEncoder; MTLBlitCommandEncoder blitCommandEncoder;
if (_pipeline.CurrentEncoder is MTLBlitCommandEncoder encoder) if (_pipeline.CurrentEncoder is MTLBlitCommandEncoder encoder)
@ -109,6 +112,7 @@ namespace Ryujinx.Graphics.Metal
public void CopyTo(BufferRange range, int layer, int level, int stride) public void CopyTo(BufferRange range, int layer, int level, int stride)
{ {
Logger.Warning?.Print(LogClass.Gpu, "Copy to");
MTLBlitCommandEncoder blitCommandEncoder; MTLBlitCommandEncoder blitCommandEncoder;
if (_pipeline.CurrentEncoder is MTLBlitCommandEncoder encoder) if (_pipeline.CurrentEncoder is MTLBlitCommandEncoder encoder)
@ -160,6 +164,7 @@ namespace Ryujinx.Graphics.Metal
// TODO: Handle array formats // TODO: Handle array formats
public unsafe void SetData(SpanOrArray<byte> data) public unsafe void SetData(SpanOrArray<byte> data)
{ {
Logger.Warning?.Print(LogClass.Gpu, "Set data");
MTLBlitCommandEncoder blitCommandEncoder; MTLBlitCommandEncoder blitCommandEncoder;
if (_pipeline.CurrentEncoder is MTLBlitCommandEncoder encoder) if (_pipeline.CurrentEncoder is MTLBlitCommandEncoder encoder)
@ -216,6 +221,7 @@ namespace Ryujinx.Graphics.Metal
public void SetData(SpanOrArray<byte> data, int layer, int level) public void SetData(SpanOrArray<byte> data, int layer, int level)
{ {
Logger.Warning?.Print(LogClass.Gpu, "Set data");
MTLBlitCommandEncoder blitCommandEncoder; MTLBlitCommandEncoder blitCommandEncoder;
if (_pipeline.CurrentEncoder is MTLBlitCommandEncoder encoder) if (_pipeline.CurrentEncoder is MTLBlitCommandEncoder encoder)
@ -257,6 +263,7 @@ namespace Ryujinx.Graphics.Metal
public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region) public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region)
{ {
Logger.Warning?.Print(LogClass.Gpu, "Set data");
MTLBlitCommandEncoder blitCommandEncoder; MTLBlitCommandEncoder blitCommandEncoder;
if (_pipeline.CurrentEncoder is MTLBlitCommandEncoder encoder) if (_pipeline.CurrentEncoder is MTLBlitCommandEncoder encoder)