Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

State and cache optimization #27

Merged
merged 8 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 0 additions & 36 deletions src/Ryujinx.Graphics.Metal/ComputePipelineCache.cs

This file was deleted.

91 changes: 44 additions & 47 deletions src/Ryujinx.Graphics.Metal/DepthStencilCache.cs
Original file line number Diff line number Diff line change
@@ -1,28 +1,11 @@
using Ryujinx.Graphics.Metal.State;
using SharpMetal.Metal;
using System.Runtime.Versioning;

namespace Ryujinx.Graphics.Metal
{
[SupportedOSPlatform("macos")]
struct DepthStencilHash
{
public struct StencilHash
{
public MTLStencilOperation StencilFailureOperation;
public MTLStencilOperation DepthFailureOperation;
public MTLStencilOperation DepthStencilPassOperation;
public MTLCompareFunction StencilCompareFunction;
public uint ReadMask;
public uint WriteMask;
}
public StencilHash FrontFace;
public StencilHash BackFace;
public MTLCompareFunction DepthCompareFunction;
public bool DepthWriteEnabled;
}

[SupportedOSPlatform("macos")]
class DepthStencilCache : StateCache<MTLDepthStencilState, MTLDepthStencilDescriptor, DepthStencilHash>
class DepthStencilCache : StateCache<MTLDepthStencilState, DepthStencilUid, DepthStencilUid>
{
private readonly MTLDevice _device;

Expand All @@ -31,41 +14,55 @@ public DepthStencilCache(MTLDevice device)
_device = device;
}

protected override DepthStencilHash GetHash(MTLDepthStencilDescriptor descriptor)
protected override DepthStencilUid GetHash(DepthStencilUid descriptor)
{
var hash = new DepthStencilHash
return descriptor;
}

protected override MTLDepthStencilState CreateValue(DepthStencilUid descriptor)
{
// Create descriptors

ref StencilUid frontUid = ref descriptor.FrontFace;

using var frontFaceStencil = new MTLStencilDescriptor
{
StencilFailureOperation = frontUid.StencilFailureOperation,
DepthFailureOperation = frontUid.DepthFailureOperation,
DepthStencilPassOperation = frontUid.DepthStencilPassOperation,
StencilCompareFunction = frontUid.StencilCompareFunction,
ReadMask = frontUid.ReadMask,
WriteMask = frontUid.WriteMask
};

ref StencilUid backUid = ref descriptor.BackFace;

using var backFaceStencil = new MTLStencilDescriptor
{
StencilFailureOperation = backUid.StencilFailureOperation,
DepthFailureOperation = backUid.DepthFailureOperation,
DepthStencilPassOperation = backUid.DepthStencilPassOperation,
StencilCompareFunction = backUid.StencilCompareFunction,
ReadMask = backUid.ReadMask,
WriteMask = backUid.WriteMask
};

var mtlDescriptor = new MTLDepthStencilDescriptor
{
// Front face
FrontFace = new DepthStencilHash.StencilHash
{
StencilFailureOperation = descriptor.FrontFaceStencil.StencilFailureOperation,
DepthFailureOperation = descriptor.FrontFaceStencil.DepthFailureOperation,
DepthStencilPassOperation = descriptor.FrontFaceStencil.DepthStencilPassOperation,
StencilCompareFunction = descriptor.FrontFaceStencil.StencilCompareFunction,
ReadMask = descriptor.FrontFaceStencil.ReadMask,
WriteMask = descriptor.FrontFaceStencil.WriteMask
},
// Back face
BackFace = new DepthStencilHash.StencilHash
{
StencilFailureOperation = descriptor.BackFaceStencil.StencilFailureOperation,
DepthFailureOperation = descriptor.BackFaceStencil.DepthFailureOperation,
DepthStencilPassOperation = descriptor.BackFaceStencil.DepthStencilPassOperation,
StencilCompareFunction = descriptor.BackFaceStencil.StencilCompareFunction,
ReadMask = descriptor.BackFaceStencil.ReadMask,
WriteMask = descriptor.BackFaceStencil.WriteMask
},
// Depth
DepthCompareFunction = descriptor.DepthCompareFunction,
DepthWriteEnabled = descriptor.DepthWriteEnabled
};

return hash;
}
if (descriptor.StencilTestEnabled)
{
mtlDescriptor.BackFaceStencil = backFaceStencil;
mtlDescriptor.FrontFaceStencil = frontFaceStencil;
}

protected override MTLDepthStencilState CreateValue(MTLDepthStencilDescriptor descriptor)
{
return _device.NewDepthStencilState(descriptor);
using (mtlDescriptor)
{
return _device.NewDepthStencilState(mtlDescriptor);
}
}
}
}
98 changes: 68 additions & 30 deletions src/Ryujinx.Graphics.Metal/EncoderState.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Metal.State;
using SharpMetal.Metal;
using System;
using System.Linq;
Expand Down Expand Up @@ -48,12 +50,29 @@ public BufferRef(Auto<DisposableBuffer> buffer, ref BufferRange range)
}
}

struct PredrawState
{
public MTLCullMode CullMode;
public DepthStencilUid DepthStencilUid;
public PrimitiveTopology Topology;
public MTLViewport[] Viewports;
}

struct RenderTargetCopy
{
public MTLScissorRect[] Scissors;
public Texture DepthStencil;
public Texture[] RenderTargets;
}

[SupportedOSPlatform("macos")]
struct EncoderState
class EncoderState
{
public MTLFunction? VertexFunction = null;
public MTLFunction? FragmentFunction = null;
public MTLFunction? ComputeFunction = null;
public Program RenderProgram = null;
public Program ComputeProgram = null;

public PipelineState Pipeline;
public DepthStencilUid DepthStencilUid;

public TextureBase[] FragmentTextures = new TextureBase[Constants.MaxTexturesPerStage];
public MTLSamplerState[] FragmentSamplers = new MTLSamplerState[Constants.MaxTexturesPerStage];
Expand All @@ -71,21 +90,14 @@ struct EncoderState
public MTLIndexType IndexType = MTLIndexType.UInt16;
public ulong IndexBufferOffset = 0;

public MTLDepthStencilState? DepthStencilState = null;

public MTLDepthClipMode DepthClipMode = MTLDepthClipMode.Clip;
public MTLCompareFunction DepthCompareFunction = MTLCompareFunction.Always;
public bool DepthWriteEnabled = false;

public float DepthBias;
public float SlopeScale;
public float Clamp;

public MTLStencilDescriptor BackFaceStencil = new();
public MTLStencilDescriptor FrontFaceStencil = new();
public int BackRefValue = 0;
public int FrontRefValue = 0;
public bool StencilTestEnabled = false;

public PrimitiveTopology Topology = PrimitiveTopology.Triangles;
public MTLCullMode CullMode = MTLCullMode.None;
Expand All @@ -102,8 +114,7 @@ struct EncoderState
public ITexture[] PreMaskRenderTargets;
public bool FramebufferUsingColorWriteMask;

public MTLColorWriteMask[] RenderTargetMasks = Enumerable.Repeat(MTLColorWriteMask.All, Constants.MaxColorAttachments).ToArray();
public BlendDescriptor?[] BlendDescriptors = new BlendDescriptor?[Constants.MaxColorAttachments];
public Array8<ColorBlendStateUid> StoredBlend;
public ColorF BlendColor = new();

public VertexBufferDescriptor[] VertexBuffers = [];
Expand All @@ -115,25 +126,52 @@ struct EncoderState
// Only to be used for present
public bool ClearLoadAction = false;

public EncoderState() { }
public EncoderState()
{
Pipeline.Initialize();
DepthStencilUid.DepthCompareFunction = MTLCompareFunction.Always;
}

public readonly EncoderState Clone()
public RenderTargetCopy InheritForClear(EncoderState other, bool depth, int singleIndex = -1)
{
// Certain state (like viewport and scissor) doesn't need to be cloned, as it is always reacreated when assigned to
EncoderState clone = this;
clone.FragmentTextures = (TextureBase[])FragmentTextures.Clone();
clone.FragmentSamplers = (MTLSamplerState[])FragmentSamplers.Clone();
clone.VertexTextures = (TextureBase[])VertexTextures.Clone();
clone.VertexSamplers = (MTLSamplerState[])VertexSamplers.Clone();
clone.ComputeTextures = (TextureBase[])ComputeTextures.Clone();
clone.ComputeSamplers = (MTLSamplerState[])ComputeSamplers.Clone();
clone.BlendDescriptors = (BlendDescriptor?[])BlendDescriptors.Clone();
clone.VertexBuffers = (VertexBufferDescriptor[])VertexBuffers.Clone();
clone.VertexAttribs = (VertexAttribDescriptor[])VertexAttribs.Clone();
clone.UniformBuffers = (BufferRef[])UniformBuffers.Clone();
clone.StorageBuffers = (BufferRef[])StorageBuffers.Clone();

return clone;
// Inherit render target related information without causing a render encoder split.

var oldState = new RenderTargetCopy
{
Scissors = other.Scissors,
RenderTargets = other.RenderTargets,
DepthStencil = other.DepthStencil
};

Scissors = other.Scissors;
RenderTargets = other.RenderTargets;
DepthStencil = other.DepthStencil;

Pipeline.ColorBlendAttachmentStateCount = other.Pipeline.ColorBlendAttachmentStateCount;
Pipeline.Internal.ColorBlendState = other.Pipeline.Internal.ColorBlendState;
Pipeline.DepthStencilFormat = other.Pipeline.DepthStencilFormat;

ref var blendStates = ref Pipeline.Internal.ColorBlendState;

// Mask out irrelevant attachments.
for (int i = 0; i < blendStates.Length; i++)
{
if (depth || (singleIndex != -1 && singleIndex != i))
{
blendStates[i].WriteMask = MTLColorWriteMask.None;
}
}

return oldState;
}

public void Restore(RenderTargetCopy copy)
{
Scissors = copy.Scissors;
RenderTargets = copy.RenderTargets;
DepthStencil = copy.DepthStencil;

Pipeline.Internal.ResetColorState();
}
}
}
Loading
Loading