Fix Cull FrontAndBack

This commit is contained in:
Isaac Marovitz 2024-06-26 12:39:25 +01:00 committed by Isaac Marovitz
parent a60643620d
commit b7ddb693bc
2 changed files with 28 additions and 6 deletions

View file

@ -90,6 +90,7 @@ namespace Ryujinx.Graphics.Metal
public PrimitiveTopology Topology = PrimitiveTopology.Triangles; public PrimitiveTopology Topology = PrimitiveTopology.Triangles;
public MTLCullMode CullMode = MTLCullMode.None; public MTLCullMode CullMode = MTLCullMode.None;
public MTLWinding Winding = MTLWinding.CounterClockwise; public MTLWinding Winding = MTLWinding.CounterClockwise;
public bool CullBoth = false;
public MTLViewport[] Viewports = []; public MTLViewport[] Viewports = [];
public MTLScissorRect[] Scissors = []; public MTLScissorRect[] Scissors = [];

View file

@ -12,6 +12,7 @@ namespace Ryujinx.Graphics.Metal
[SupportedOSPlatform("macos")] [SupportedOSPlatform("macos")]
struct EncoderStateManager : IDisposable struct EncoderStateManager : IDisposable
{ {
private readonly MTLDevice _device;
private readonly Pipeline _pipeline; private readonly Pipeline _pipeline;
private readonly BufferManager _bufferManager; private readonly BufferManager _bufferManager;
@ -35,6 +36,7 @@ namespace Ryujinx.Graphics.Metal
public unsafe EncoderStateManager(MTLDevice device, BufferManager bufferManager, Pipeline pipeline) public unsafe EncoderStateManager(MTLDevice device, BufferManager bufferManager, Pipeline pipeline)
{ {
_device = device;
_pipeline = pipeline; _pipeline = pipeline;
_bufferManager = bufferManager; _bufferManager = bufferManager;
@ -533,7 +535,7 @@ namespace Ryujinx.Graphics.Metal
descriptor.FrontFaceStencil = _currentState.FrontFaceStencil; descriptor.FrontFaceStencil = _currentState.FrontFaceStencil;
} }
_currentState.DepthStencilState = _depthStencilCache.GetOrCreate(descriptor); _currentState.DepthStencilState = _device.NewDepthStencilState(descriptor);
UpdateStencilRefValue(stencilTest.FrontFuncRef, stencilTest.BackFuncRef); UpdateStencilRefValue(stencilTest.FrontFuncRef, stencilTest.BackFuncRef);
@ -547,7 +549,7 @@ namespace Ryujinx.Graphics.Metal
public void UpdateDepthState(DepthTestDescriptor depthTest) public void UpdateDepthState(DepthTestDescriptor depthTest)
{ {
_currentState.DepthCompareFunction = depthTest.TestEnable ? depthTest.Func.Convert() : MTLCompareFunction.Always; _currentState.DepthCompareFunction = depthTest.TestEnable ? depthTest.Func.Convert() : MTLCompareFunction.Always;
_currentState.DepthWriteEnabled = depthTest.WriteEnable; _currentState.DepthWriteEnabled = depthTest.TestEnable && depthTest.WriteEnable;
var descriptor = new MTLDepthStencilDescriptor var descriptor = new MTLDepthStencilDescriptor
{ {
@ -561,7 +563,7 @@ namespace Ryujinx.Graphics.Metal
descriptor.FrontFaceStencil = _currentState.FrontFaceStencil; descriptor.FrontFaceStencil = _currentState.FrontFaceStencil;
} }
_currentState.DepthStencilState = _depthStencilCache.GetOrCreate(descriptor); _currentState.DepthStencilState = _device.NewDepthStencilState(descriptor);
// Mark dirty // Mark dirty
_currentState.Dirty |= DirtyFlags.DepthStencil; _currentState.Dirty |= DirtyFlags.DepthStencil;
@ -741,18 +743,27 @@ namespace Ryujinx.Graphics.Metal
// Inlineable // Inlineable
public void UpdateCullMode(bool enable, Face face) public void UpdateCullMode(bool enable, Face face)
{ {
var dirtyScissor = (face == Face.FrontAndBack) != _currentState.CullBoth;
_currentState.CullMode = enable ? face.Convert() : MTLCullMode.None; _currentState.CullMode = enable ? face.Convert() : MTLCullMode.None;
_currentState.CullBoth = face == Face.FrontAndBack;
// Inline update // Inline update
if (_pipeline.CurrentEncoderType == EncoderType.Render && _pipeline.CurrentEncoder != null) if (_pipeline.CurrentEncoderType == EncoderType.Render && _pipeline.CurrentEncoder != null)
{ {
var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value); var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value);
SetCullMode(renderCommandEncoder); SetCullMode(renderCommandEncoder);
SetScissors(renderCommandEncoder);
return; return;
} }
// Mark dirty // Mark dirty
_currentState.Dirty |= DirtyFlags.CullMode; _currentState.Dirty |= DirtyFlags.CullMode;
if (dirtyScissor)
{
_currentState.Dirty |= DirtyFlags.Scissors;
}
} }
// Inlineable // Inlineable
@ -862,11 +873,21 @@ namespace Ryujinx.Graphics.Metal
private unsafe void SetScissors(MTLRenderCommandEncoder renderCommandEncoder) private unsafe void SetScissors(MTLRenderCommandEncoder renderCommandEncoder)
{ {
if (_currentState.Scissors.Length > 0) var isTriangles = (_currentState.Topology == PrimitiveTopology.Triangles) ||
(_currentState.Topology == PrimitiveTopology.TriangleStrip);
if (_currentState.CullBoth && isTriangles)
{ {
fixed (MTLScissorRect* pMtlScissors = _currentState.Scissors) renderCommandEncoder.SetScissorRect(new MTLScissorRect { x = 0, y = 0, width = 0, height = 0});
}
else
{
if (_currentState.Scissors.Length > 0)
{ {
renderCommandEncoder.SetScissorRects((IntPtr)pMtlScissors, (ulong)_currentState.Scissors.Length); fixed (MTLScissorRect* pMtlScissors = _currentState.Scissors)
{
renderCommandEncoder.SetScissorRects((IntPtr)pMtlScissors, (ulong)_currentState.Scissors.Length);
}
} }
} }
} }