mirror of
https://github.com/Ryujinx/Ryujinx.git
synced 2024-12-19 02:12:24 +00:00
Seizure my beloved is working
This commit is contained in:
parent
6d722d83ba
commit
aaa140e510
5 changed files with 109 additions and 39 deletions
|
@ -4,6 +4,7 @@ using Ryujinx.Graphics.GAL;
|
|||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using SharpMetal.Foundation;
|
||||
using SharpMetal.Metal;
|
||||
using SharpMetal.QuartzCore;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
@ -14,25 +15,43 @@ namespace Ryujinx.Graphics.Metal
|
|||
public sealed class MetalRenderer : IRenderer
|
||||
{
|
||||
private readonly MTLDevice _device;
|
||||
private readonly Window _window;
|
||||
private readonly Pipeline _pipeline;
|
||||
private readonly MTLCommandQueue _queue;
|
||||
private readonly Func<CAMetalLayer> _getMetalLayer;
|
||||
|
||||
private Pipeline _pipeline;
|
||||
private Window _window;
|
||||
|
||||
public event EventHandler<ScreenCaptureImageInfo> ScreenCaptured;
|
||||
public bool PreferThreading => true;
|
||||
public IPipeline Pipeline => _pipeline;
|
||||
public IWindow Window => _window;
|
||||
|
||||
public MetalRenderer()
|
||||
public MetalRenderer(Func<CAMetalLayer> metalLayer)
|
||||
{
|
||||
_device = MTLDevice.CreateSystemDefaultDevice();
|
||||
_queue = _device.NewCommandQueue();
|
||||
_pipeline = new Pipeline(_device, _queue);
|
||||
_window = new Window(this);
|
||||
_getMetalLayer = metalLayer;
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -96,7 +115,10 @@ namespace Ryujinx.Graphics.Metal
|
|||
|
||||
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)
|
||||
|
|
|
@ -4,6 +4,7 @@ using Ryujinx.Graphics.GAL;
|
|||
using Ryujinx.Graphics.Shader;
|
||||
using SharpMetal.Foundation;
|
||||
using SharpMetal.Metal;
|
||||
using SharpMetal.QuartzCore;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
@ -28,8 +29,10 @@ namespace Ryujinx.Graphics.Metal
|
|||
private MTLBuffer _indexBuffer;
|
||||
private MTLIndexType _indexType;
|
||||
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;
|
||||
_mtlCommandQueue = commandQueue;
|
||||
|
@ -49,13 +52,17 @@ namespace Ryujinx.Graphics.Metal
|
|||
// TODO: Recreate descriptor and encoder state as needed
|
||||
var renderPipelineDescriptor = new MTLRenderPipelineDescriptor();
|
||||
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)
|
||||
{
|
||||
Logger.Error?.PrintMsg(LogClass.Gpu, $"Failed to create Render Pipeline State: {StringHelper.String(error.LocalizedDescription)}");
|
||||
}
|
||||
|
||||
_renderEncoderState = new RenderEncoderState(renderPipelineState, _device);
|
||||
//
|
||||
|
||||
_commandBuffer = _mtlCommandQueue.CommandBuffer();
|
||||
|
@ -68,6 +75,7 @@ namespace Ryujinx.Graphics.Metal
|
|||
_currentEncoder.EndEncoding();
|
||||
_currentEncoder = null;
|
||||
}
|
||||
Logger.Warning?.Print(LogClass.Gpu, "Current pass ended");
|
||||
}
|
||||
|
||||
public MTLRenderCommandEncoder BeginRenderPass()
|
||||
|
@ -77,6 +85,7 @@ namespace Ryujinx.Graphics.Metal
|
|||
var descriptor = new MTLRenderPassDescriptor();
|
||||
var renderCommandEncoder = _commandBuffer.RenderCommandEncoder(descriptor);
|
||||
_renderEncoderState.SetEncoderState(renderCommandEncoder);
|
||||
Logger.Warning?.Print(LogClass.Gpu, "Began render pass");
|
||||
|
||||
_currentEncoder = renderCommandEncoder;
|
||||
return renderCommandEncoder;
|
||||
|
@ -88,6 +97,7 @@ namespace Ryujinx.Graphics.Metal
|
|||
|
||||
var descriptor = new MTLBlitPassDescriptor();
|
||||
var blitCommandEncoder = _commandBuffer.BlitCommandEncoder(descriptor);
|
||||
Logger.Warning?.Print(LogClass.Gpu, "Began blit pass");
|
||||
|
||||
_currentEncoder = blitCommandEncoder;
|
||||
return blitCommandEncoder;
|
||||
|
@ -99,18 +109,43 @@ namespace Ryujinx.Graphics.Metal
|
|||
|
||||
var descriptor = new MTLComputePassDescriptor();
|
||||
var computeCommandEncoder = _commandBuffer.ComputeCommandEncoder(descriptor);
|
||||
Logger.Warning?.Print(LogClass.Gpu, "Began compute pass");
|
||||
|
||||
_currentEncoder = computeCommandEncoder;
|
||||
return computeCommandEncoder;
|
||||
}
|
||||
|
||||
public void Present()
|
||||
public void Present(CAMetalDrawable drawable)
|
||||
{
|
||||
EndCurrentPass();
|
||||
|
||||
// TODO: Give command buffer a valid MTLDrawable
|
||||
// _commandBuffer.PresentDrawable();
|
||||
// _commandBuffer.Commit();
|
||||
var descriptor = new MTLRenderPassDescriptor();
|
||||
descriptor.ColorAttachments.Object(0).Texture = drawable.Texture;
|
||||
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();
|
||||
}
|
||||
|
@ -147,7 +182,7 @@ namespace Ryujinx.Graphics.Metal
|
|||
|
||||
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,
|
||||
|
|
|
@ -17,23 +17,23 @@ namespace Ryujinx.Graphics.Metal
|
|||
private MTLStencilDescriptor _backFaceStencil = null;
|
||||
private MTLStencilDescriptor _frontFaceStencil = null;
|
||||
|
||||
public MTLRenderPipelineState RenderPipelineState;
|
||||
public MTLRenderPipelineState CopyPipeline;
|
||||
public PrimitiveTopology Topology = PrimitiveTopology.Triangles;
|
||||
public MTLCullMode CullMode = MTLCullMode.None;
|
||||
public MTLWinding Winding = MTLWinding.Clockwise;
|
||||
|
||||
public RenderEncoderState(MTLRenderPipelineState renderPipelineState, MTLDevice device)
|
||||
public RenderEncoderState(MTLRenderPipelineState copyPipeline, MTLDevice device)
|
||||
{
|
||||
_device = device;
|
||||
RenderPipelineState = renderPipelineState;
|
||||
CopyPipeline = copyPipeline;
|
||||
}
|
||||
|
||||
public void SetEncoderState(MTLRenderCommandEncoder renderCommandEncoder)
|
||||
{
|
||||
renderCommandEncoder.SetRenderPipelineState(RenderPipelineState);
|
||||
renderCommandEncoder.SetRenderPipelineState(CopyPipeline);
|
||||
renderCommandEncoder.SetCullMode(CullMode);
|
||||
renderCommandEncoder.SetFrontFacingWinding(Winding);
|
||||
renderCommandEncoder.SetDepthStencilState(_depthStencilState);
|
||||
// renderCommandEncoder.SetDepthStencilState(_depthStencilState);
|
||||
}
|
||||
|
||||
public MTLDepthStencilState UpdateStencilState(MTLStencilDescriptor backFace, MTLStencilDescriptor frontFace)
|
||||
|
|
|
@ -2,29 +2,35 @@
|
|||
|
||||
using namespace metal;
|
||||
|
||||
struct TexCoordIn {
|
||||
float4 tex_coord_in_data;
|
||||
constant float2 quadVertices[] = {
|
||||
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]],
|
||||
constant TexCoordIn& tex_coord_in [[buffer(1)]]) {
|
||||
int low = vertexID & 1;
|
||||
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];
|
||||
struct CopyVertexOut {
|
||||
float4 position [[position]];
|
||||
float2 uv;
|
||||
};
|
||||
|
||||
float4 position;
|
||||
position.x = (float(low) - 0.5) * 2.0;
|
||||
position.y = (float(high) - 0.5) * 2.0;
|
||||
position.z = 0.0;
|
||||
position.w = 1.0;
|
||||
vertex CopyVertexOut vertexMain(unsigned short vid [[vertex_id]]) {
|
||||
float2 position = quadVertices[vid];
|
||||
|
||||
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]],
|
||||
texture2d<float> tex [[texture(0)]]) {
|
||||
float4 color = tex.sample(metal::address::clamp_to_edge, tex_coord);
|
||||
return color;
|
||||
fragment float4 fragmentMain(CopyVertexOut in [[stage_in]],
|
||||
texture2d<float> tex) {
|
||||
constexpr sampler sam(min_filter::nearest, mag_filter::nearest, mip_filter::none);
|
||||
|
||||
float3 color = tex.sample(sam, in.uv).xyz;
|
||||
return float4(color, 1.0f);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ using System.Runtime.Versioning;
|
|||
namespace Ryujinx.Graphics.Metal
|
||||
{
|
||||
[SupportedOSPlatform("macos")]
|
||||
class Texture : ITexture, IDisposable
|
||||
public class Texture : ITexture, IDisposable
|
||||
{
|
||||
private readonly TextureCreateInfo _info;
|
||||
private readonly Pipeline _pipeline;
|
||||
|
@ -23,6 +23,7 @@ namespace Ryujinx.Graphics.Metal
|
|||
|
||||
public Texture(MTLDevice device, Pipeline pipeline, TextureCreateInfo info)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Gpu, "Texture init");
|
||||
_device = device;
|
||||
_pipeline = pipeline;
|
||||
_info = info;
|
||||
|
@ -50,6 +51,7 @@ namespace Ryujinx.Graphics.Metal
|
|||
|
||||
public void CopyTo(ITexture destination, int firstLayer, int firstLevel)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Gpu, "Copy to");
|
||||
MTLBlitCommandEncoder blitCommandEncoder;
|
||||
|
||||
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)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Gpu, "Copy to");
|
||||
MTLBlitCommandEncoder blitCommandEncoder;
|
||||
|
||||
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)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Gpu, "Copy to");
|
||||
MTLBlitCommandEncoder blitCommandEncoder;
|
||||
|
||||
if (_pipeline.CurrentEncoder is MTLBlitCommandEncoder encoder)
|
||||
|
@ -160,6 +164,7 @@ namespace Ryujinx.Graphics.Metal
|
|||
// TODO: Handle array formats
|
||||
public unsafe void SetData(SpanOrArray<byte> data)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Gpu, "Set data");
|
||||
MTLBlitCommandEncoder blitCommandEncoder;
|
||||
|
||||
if (_pipeline.CurrentEncoder is MTLBlitCommandEncoder encoder)
|
||||
|
@ -216,6 +221,7 @@ namespace Ryujinx.Graphics.Metal
|
|||
|
||||
public void SetData(SpanOrArray<byte> data, int layer, int level)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Gpu, "Set data");
|
||||
MTLBlitCommandEncoder blitCommandEncoder;
|
||||
|
||||
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)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Gpu, "Set data");
|
||||
MTLBlitCommandEncoder blitCommandEncoder;
|
||||
|
||||
if (_pipeline.CurrentEncoder is MTLBlitCommandEncoder encoder)
|
||||
|
|
Loading…
Reference in a new issue