up to date with 08126b26b1db39b2eb11be81b4e2ffd613b0bdbf
This commit is contained in:
parent
6d513cad1e
commit
93e5ff0137
@ -1,3 +1,4 @@
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
using SharpMetal.Foundation;
|
||||
@ -15,14 +16,11 @@ namespace Ryujinx.Graphics.Metal
|
||||
private readonly MTLCommandQueue _mtlCommandQueue;
|
||||
|
||||
private MTLCommandBuffer _commandBuffer;
|
||||
private MTLRenderCommandEncoder _renderCommandEncoder;
|
||||
private MTLRenderPipelineState _renderPipelineState;
|
||||
private MTLBlitCommandEncoder _blitCommandEncoder;
|
||||
private MTLCommandEncoder _currentEncoder;
|
||||
|
||||
public MTLRenderCommandEncoder RenderCommandEncoder => _renderCommandEncoder;
|
||||
public MTLBlitCommandEncoder BlitCommandEncoder => _blitCommandEncoder;
|
||||
public MTLCommandEncoder CurrentEncoder;
|
||||
|
||||
private PrimitiveTopology _topology;
|
||||
private RenderEncoderState _renderEncoderState;
|
||||
|
||||
private MTLBuffer _indexBuffer;
|
||||
private MTLIndexType _indexType;
|
||||
@ -35,35 +33,56 @@ namespace Ryujinx.Graphics.Metal
|
||||
|
||||
var renderPipelineDescriptor = new MTLRenderPipelineDescriptor();
|
||||
var error = new NSError(IntPtr.Zero);
|
||||
_renderPipelineState = _device.NewRenderPipelineState(renderPipelineDescriptor, ref error);
|
||||
_renderEncoderState = new(_device.NewRenderPipelineState(renderPipelineDescriptor, ref error));
|
||||
if (error != IntPtr.Zero)
|
||||
{
|
||||
// throw new Exception($"Failed to create render pipeline state! {StringHelp}");
|
||||
throw new Exception($"Failed to create render pipeline state!");
|
||||
Logger.Error?.PrintMsg(LogClass.Gpu, $"Failed to create Render Pipeline State: {StringHelper.String(error.LocalizedDescription)}");
|
||||
}
|
||||
|
||||
CreateCommandBuffer();
|
||||
_commandBuffer = _mtlCommandQueue.CommandBuffer();
|
||||
}
|
||||
|
||||
public void EndCurrentPass()
|
||||
{
|
||||
if (_currentEncoder != null)
|
||||
{
|
||||
_currentEncoder.EndEncoding();
|
||||
_currentEncoder = null;
|
||||
}
|
||||
}
|
||||
|
||||
public MTLRenderCommandEncoder BeginRenderPass()
|
||||
{
|
||||
EndCurrentPass();
|
||||
|
||||
var descriptor = new MTLRenderPassDescriptor { };
|
||||
var renderCommandEncoder = _commandBuffer.RenderCommandEncoder(descriptor);
|
||||
_renderEncoderState.SetEncoderState(renderCommandEncoder);
|
||||
|
||||
_currentEncoder = renderCommandEncoder;
|
||||
return renderCommandEncoder;
|
||||
}
|
||||
|
||||
public MTLBlitCommandEncoder BeginBlitPass()
|
||||
{
|
||||
EndCurrentPass();
|
||||
|
||||
var descriptor = new MTLBlitPassDescriptor { };
|
||||
var blitCommandEncoder = _commandBuffer.BlitCommandEncoder(descriptor);
|
||||
|
||||
_currentEncoder = blitCommandEncoder;
|
||||
return blitCommandEncoder;
|
||||
}
|
||||
|
||||
public void Present()
|
||||
{
|
||||
_renderCommandEncoder.EndEncoding();
|
||||
_blitCommandEncoder.EndEncoding();
|
||||
EndCurrentPass();
|
||||
|
||||
// TODO: Give command buffer a valid MTLDrawable
|
||||
// _commandBuffer.PresentDrawable();
|
||||
_commandBuffer.Commit();
|
||||
|
||||
CreateCommandBuffer();
|
||||
}
|
||||
|
||||
public void CreateCommandBuffer()
|
||||
{
|
||||
_commandBuffer = _mtlCommandQueue.CommandBuffer();
|
||||
|
||||
_renderCommandEncoder = _commandBuffer.RenderCommandEncoder(new MTLRenderPassDescriptor());
|
||||
_renderCommandEncoder.SetRenderPipelineState(_renderPipelineState);
|
||||
|
||||
_blitCommandEncoder = _commandBuffer.BlitCommandEncoder(new MTLBlitPassDescriptor());
|
||||
}
|
||||
|
||||
public void Barrier()
|
||||
@ -73,7 +92,27 @@ namespace Ryujinx.Graphics.Metal
|
||||
|
||||
public void ClearBuffer(BufferHandle destination, int offset, int size, uint value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
MTLBlitCommandEncoder blitCommandEncoder;
|
||||
|
||||
if (_currentEncoder is MTLBlitCommandEncoder encoder)
|
||||
{
|
||||
blitCommandEncoder = encoder;
|
||||
}
|
||||
else
|
||||
{
|
||||
blitCommandEncoder = BeginBlitPass();
|
||||
}
|
||||
|
||||
// Might need a closer look, range's count, lower, and upper bound
|
||||
// must be a multiple of 4
|
||||
MTLBuffer mtlBuffer = new(Unsafe.As<BufferHandle, IntPtr>(ref destination));
|
||||
blitCommandEncoder.FillBuffer(mtlBuffer,
|
||||
new NSRange
|
||||
{
|
||||
location = (ulong)offset,
|
||||
length = (ulong)size
|
||||
},
|
||||
(byte)value);
|
||||
}
|
||||
|
||||
public void ClearRenderTargetColor(int index, int layer, int layerCount, uint componentMask, ColorF color)
|
||||
@ -104,18 +143,40 @@ namespace Ryujinx.Graphics.Metal
|
||||
|
||||
public void Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance)
|
||||
{
|
||||
// TODO: Support topology re-indexing to provide support for TriangleFans
|
||||
var _primitiveType = _topology.Convert();
|
||||
MTLRenderCommandEncoder renderCommandEncoder;
|
||||
|
||||
_renderCommandEncoder.DrawPrimitives(_primitiveType, (ulong)firstVertex, (ulong)vertexCount, (ulong)instanceCount, (ulong)firstInstance);
|
||||
if (_currentEncoder is MTLRenderCommandEncoder encoder)
|
||||
{
|
||||
renderCommandEncoder = encoder;
|
||||
}
|
||||
else
|
||||
{
|
||||
renderCommandEncoder = BeginRenderPass();
|
||||
}
|
||||
|
||||
// TODO: Support topology re-indexing to provide support for TriangleFans
|
||||
var primitiveType = _renderEncoderState.Topology.Convert();
|
||||
|
||||
renderCommandEncoder.DrawPrimitives(primitiveType, (ulong)firstVertex, (ulong)vertexCount, (ulong)instanceCount, (ulong)firstInstance);
|
||||
}
|
||||
|
||||
public void DrawIndexed(int indexCount, int instanceCount, int firstIndex, int firstVertex, int firstInstance)
|
||||
{
|
||||
// TODO: Support topology re-indexing to provide support for TriangleFans
|
||||
var _primitiveType = _topology.Convert();
|
||||
MTLRenderCommandEncoder renderCommandEncoder;
|
||||
|
||||
_renderCommandEncoder.DrawIndexedPrimitives(_primitiveType, (ulong)indexCount, _indexType, _indexBuffer, _indexBufferOffset, (ulong)instanceCount, firstVertex, (ulong)firstInstance);
|
||||
if (_currentEncoder is MTLRenderCommandEncoder encoder)
|
||||
{
|
||||
renderCommandEncoder = encoder;
|
||||
}
|
||||
else
|
||||
{
|
||||
renderCommandEncoder = BeginRenderPass();
|
||||
}
|
||||
|
||||
// TODO: Support topology re-indexing to provide support for TriangleFans
|
||||
var primitiveType = _renderEncoderState.Topology.Convert();
|
||||
|
||||
renderCommandEncoder.DrawIndexedPrimitives(primitiveType, (ulong)indexCount, _indexType, _indexBuffer, _indexBufferOffset, (ulong)instanceCount, firstVertex, (ulong)firstInstance);
|
||||
}
|
||||
|
||||
public void DrawIndexedIndirect(BufferRange indirectBuffer)
|
||||
@ -180,12 +241,26 @@ namespace Ryujinx.Graphics.Metal
|
||||
|
||||
public void SetFaceCulling(bool enable, Face face)
|
||||
{
|
||||
_renderCommandEncoder.SetCullMode(enable ? face.Convert() : MTLCullMode.None);
|
||||
var cullMode = enable ? face.Convert() : MTLCullMode.None;
|
||||
|
||||
if (_currentEncoder is MTLRenderCommandEncoder renderCommandEncoder)
|
||||
{
|
||||
renderCommandEncoder.SetCullMode(cullMode);
|
||||
}
|
||||
|
||||
_renderEncoderState.CullMode = cullMode;
|
||||
}
|
||||
|
||||
public void SetFrontFace(FrontFace frontFace)
|
||||
{
|
||||
_renderCommandEncoder.SetFrontFacingWinding(frontFace.Convert());
|
||||
var winding = frontFace.Convert();
|
||||
|
||||
if (_currentEncoder is MTLRenderCommandEncoder renderCommandEncoder)
|
||||
{
|
||||
renderCommandEncoder.SetFrontFacingWinding(winding);
|
||||
}
|
||||
|
||||
_renderEncoderState.Winding = winding;
|
||||
}
|
||||
|
||||
public void SetIndexBuffer(BufferRange buffer, IndexType type)
|
||||
@ -244,7 +319,7 @@ namespace Ryujinx.Graphics.Metal
|
||||
|
||||
public void SetPrimitiveTopology(PrimitiveTopology topology)
|
||||
{
|
||||
_topology = topology;
|
||||
_renderEncoderState.Topology = topology;
|
||||
}
|
||||
|
||||
public void SetProgram(IProgram program)
|
||||
|
27
src/Ryujinx.Graphics.Metal/RenderEncoderState.cs
Normal file
27
src/Ryujinx.Graphics.Metal/RenderEncoderState.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using SharpMetal.Metal;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Ryujinx.Graphics.Metal
|
||||
{
|
||||
[SupportedOSPlatform("macos")]
|
||||
struct RenderEncoderState
|
||||
{
|
||||
public MTLRenderPipelineState RenderPipelineState;
|
||||
public PrimitiveTopology Topology = PrimitiveTopology.Triangles;
|
||||
public MTLCullMode CullMode = MTLCullMode.None;
|
||||
public MTLWinding Winding = MTLWinding.Clockwise;
|
||||
|
||||
public RenderEncoderState(MTLRenderPipelineState renderPipelineState)
|
||||
{
|
||||
RenderPipelineState = renderPipelineState;
|
||||
}
|
||||
|
||||
public void SetEncoderState(MTLRenderCommandEncoder renderCommandEncoder)
|
||||
{
|
||||
renderCommandEncoder.SetRenderPipelineState(RenderPipelineState);
|
||||
renderCommandEncoder.SetCullMode(CullMode);
|
||||
renderCommandEncoder.SetFrontFacingWinding(Winding);
|
||||
}
|
||||
}
|
||||
}
|
30
src/Ryujinx.Graphics.Metal/StringHelper.cs
Normal file
30
src/Ryujinx.Graphics.Metal/StringHelper.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using SharpMetal.Foundation;
|
||||
using SharpMetal.ObjectiveCCore;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Ryujinx.Graphics.Metal
|
||||
{
|
||||
[SupportedOSPlatform("macos")]
|
||||
public class StringHelper
|
||||
{
|
||||
public static NSString NSString(string source)
|
||||
{
|
||||
return new(ObjectiveC.IntPtr_objc_msgSend(new ObjectiveCClass("NSString"), "stringWithUTF8String:", source));
|
||||
}
|
||||
|
||||
public static unsafe string String(NSString source)
|
||||
{
|
||||
char[] sourceBuffer = new char[source.Length];
|
||||
fixed (char* pSourceBuffer = sourceBuffer)
|
||||
{
|
||||
ObjectiveC.bool_objc_msgSend(source,
|
||||
"getCString:maxLength:encoding:",
|
||||
pSourceBuffer,
|
||||
source.MaximumLengthOfBytes(NSStringEncoding.UTF16) + 1,
|
||||
(ulong)NSStringEncoding.UTF16);
|
||||
}
|
||||
|
||||
return new string(sourceBuffer);
|
||||
}
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@ namespace Ryujinx.Graphics.Metal
|
||||
private readonly MTLDevice _device;
|
||||
|
||||
public MTLTexture MTLTexture;
|
||||
public TextureCreateInfo Info => Info;
|
||||
public TextureCreateInfo Info => _info;
|
||||
public int Width => Info.Width;
|
||||
public int Height => Info.Height;
|
||||
|
||||
@ -46,9 +46,20 @@ namespace Ryujinx.Graphics.Metal
|
||||
|
||||
public void CopyTo(ITexture destination, int firstLayer, int firstLevel)
|
||||
{
|
||||
MTLBlitCommandEncoder blitCommandEncoder;
|
||||
|
||||
if (_pipeline.CurrentEncoder is MTLBlitCommandEncoder encoder)
|
||||
{
|
||||
blitCommandEncoder = encoder;
|
||||
}
|
||||
else
|
||||
{
|
||||
blitCommandEncoder = _pipeline.BeginBlitPass();
|
||||
}
|
||||
|
||||
if (destination is Texture destinationTexture)
|
||||
{
|
||||
_pipeline.BlitCommandEncoder.CopyFromTexture(
|
||||
blitCommandEncoder.CopyFromTexture(
|
||||
MTLTexture,
|
||||
(ulong)firstLayer,
|
||||
(ulong)firstLevel,
|
||||
@ -62,9 +73,20 @@ namespace Ryujinx.Graphics.Metal
|
||||
|
||||
public void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel)
|
||||
{
|
||||
MTLBlitCommandEncoder blitCommandEncoder;
|
||||
|
||||
if (_pipeline.CurrentEncoder is MTLBlitCommandEncoder encoder)
|
||||
{
|
||||
blitCommandEncoder = encoder;
|
||||
}
|
||||
else
|
||||
{
|
||||
blitCommandEncoder = _pipeline.BeginBlitPass();
|
||||
}
|
||||
|
||||
if (destination is Texture destinationTexture)
|
||||
{
|
||||
_pipeline.BlitCommandEncoder.CopyFromTexture(
|
||||
blitCommandEncoder.CopyFromTexture(
|
||||
MTLTexture,
|
||||
(ulong)srcLayer,
|
||||
(ulong)srcLevel,
|
||||
@ -111,25 +133,83 @@ namespace Ryujinx.Graphics.Metal
|
||||
|
||||
public void SetData(SpanOrArray<byte> data, int layer, int level)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
MTLBlitCommandEncoder blitCommandEncoder;
|
||||
|
||||
if (_pipeline.CurrentEncoder is MTLBlitCommandEncoder encoder)
|
||||
{
|
||||
blitCommandEncoder = encoder;
|
||||
}
|
||||
else
|
||||
{
|
||||
blitCommandEncoder = _pipeline.BeginBlitPass();
|
||||
}
|
||||
|
||||
ulong bytesPerRow = (ulong)Info.GetMipStride(level);
|
||||
ulong bytesPerImage = 0;
|
||||
if (MTLTexture.TextureType == MTLTextureType.Type3D)
|
||||
{
|
||||
bytesPerImage = bytesPerRow * (ulong)Info.Height;
|
||||
}
|
||||
|
||||
unsafe
|
||||
{
|
||||
var dataSpan = data.Span;
|
||||
var mtlBuffer = _device.NewBuffer((ulong)dataSpan.Length, MTLResourceOptions.ResourceStorageModeShared);
|
||||
var bufferSpan = new Span<byte>(mtlBuffer.Contents.ToPointer(), dataSpan.Length);
|
||||
dataSpan.CopyTo(bufferSpan);
|
||||
|
||||
blitCommandEncoder.CopyFromBuffer(
|
||||
mtlBuffer,
|
||||
0,
|
||||
bytesPerRow,
|
||||
bytesPerImage,
|
||||
new MTLSize { width = MTLTexture.Width, height = MTLTexture.Height },
|
||||
MTLTexture,
|
||||
(ulong)layer,
|
||||
(ulong)level,
|
||||
new MTLOrigin()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe 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)
|
||||
{
|
||||
// TODO: Figure out bytesPerRow
|
||||
// For an ordinary or packed pixel format, the stride, in bytes, between rows of source data.
|
||||
// For a compressed pixel format, the stride is the number of bytes from the beginning of one row of blocks to the beginning of the next.
|
||||
if (MTLTexture.IsSparse)
|
||||
ulong bytesPerRow = 0;
|
||||
var mtlRegion = new MTLRegion
|
||||
{
|
||||
origin = new MTLOrigin { x = (ulong)region.X, y = (ulong)region.Y },
|
||||
size = new MTLSize { width = (ulong)region.Width, height = (ulong)region.Height },
|
||||
};
|
||||
MTLBlitCommandEncoder blitCommandEncoder;
|
||||
|
||||
fixed (byte* pData = data.Span)
|
||||
if (_pipeline.CurrentEncoder is MTLBlitCommandEncoder encoder)
|
||||
{
|
||||
MTLTexture.ReplaceRegion(mtlRegion, (ulong)level, (ulong)layer, new IntPtr(pData), bytesPerRow, 0);
|
||||
blitCommandEncoder = encoder;
|
||||
}
|
||||
else
|
||||
{
|
||||
blitCommandEncoder = _pipeline.BeginBlitPass();
|
||||
}
|
||||
|
||||
ulong bytesPerRow = (ulong)Info.GetMipStride(level);
|
||||
ulong bytesPerImage = 0;
|
||||
if (MTLTexture.TextureType == MTLTextureType.Type3D)
|
||||
{
|
||||
bytesPerImage = bytesPerRow * (ulong)Info.Height;
|
||||
}
|
||||
|
||||
unsafe
|
||||
{
|
||||
var dataSpan = data.Span;
|
||||
var mtlBuffer = _device.NewBuffer((ulong)dataSpan.Length, MTLResourceOptions.ResourceStorageModeShared);
|
||||
var bufferSpan = new Span<byte>(mtlBuffer.Contents.ToPointer(), dataSpan.Length);
|
||||
dataSpan.CopyTo(bufferSpan);
|
||||
|
||||
blitCommandEncoder.CopyFromBuffer(
|
||||
mtlBuffer,
|
||||
0,
|
||||
bytesPerRow,
|
||||
bytesPerImage,
|
||||
new MTLSize { width = (ulong)region.Width, height = (ulong)region.Height },
|
||||
MTLTexture,
|
||||
(ulong)layer,
|
||||
(ulong)level,
|
||||
new MTLOrigin { x = (ulong)region.X, y = (ulong)region.Y }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user