implement pipeline cache
This commit is contained in:
parent
f2490347af
commit
bab9542020
4 changed files with 191 additions and 12 deletions
|
@ -9,5 +9,10 @@ namespace Ryujinx.Graphics.Metal
|
|||
public const int MaxTexturesPerStage = 64;
|
||||
public const int MaxCommandBuffersPerQueue = 16;
|
||||
public const int MaxTextureBindings = MaxTexturesPerStage * MaxShaderStages;
|
||||
public const int MaxColorAttachments = 8;
|
||||
// TODO: Check this value
|
||||
public const int MaxVertexAttributes = 16;
|
||||
// TODO: Check this value
|
||||
public const int MaxVertexLayouts = 16;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,8 +27,6 @@ namespace Ryujinx.Graphics.Metal
|
|||
[SupportedOSPlatform("macos")]
|
||||
public struct EncoderState
|
||||
{
|
||||
public const int MaxColorAttachments = 8;
|
||||
|
||||
public MTLFunction? VertexFunction = null;
|
||||
public MTLFunction? FragmentFunction = null;
|
||||
|
||||
|
@ -64,7 +62,7 @@ namespace Ryujinx.Graphics.Metal
|
|||
|
||||
// Changes to attachments take recreation!
|
||||
public MTLTexture DepthStencil = default;
|
||||
public MTLTexture[] RenderTargets = new MTLTexture[MaxColorAttachments];
|
||||
public MTLTexture[] RenderTargets = new MTLTexture[Constants.MaxColorAttachments];
|
||||
public Dictionary<int, BlendDescriptor> BlendDescriptors = new();
|
||||
public ColorF BlendColor = new();
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@ namespace Ryujinx.Graphics.Metal
|
|||
private readonly MTLDevice _device;
|
||||
private readonly Pipeline _pipeline;
|
||||
|
||||
private readonly RenderPipelineCache RenderPipelineCache;
|
||||
|
||||
private EncoderState _currentState = new();
|
||||
private EncoderState _backState = new();
|
||||
|
||||
|
@ -28,6 +30,7 @@ namespace Ryujinx.Graphics.Metal
|
|||
{
|
||||
_device = device;
|
||||
_pipeline = pipeline;
|
||||
RenderPipelineCache = new(device);
|
||||
}
|
||||
|
||||
public void SwapStates()
|
||||
|
@ -45,7 +48,7 @@ namespace Ryujinx.Graphics.Metal
|
|||
// Initialise Pass & State
|
||||
var renderPassDescriptor = new MTLRenderPassDescriptor();
|
||||
|
||||
for (int i = 0; i < EncoderState.MaxColorAttachments; i++)
|
||||
for (int i = 0; i < Constants.MaxColorAttachments; i++)
|
||||
{
|
||||
if (_currentState.RenderTargets[i] != IntPtr.Zero)
|
||||
{
|
||||
|
@ -131,7 +134,7 @@ namespace Ryujinx.Graphics.Metal
|
|||
private void SetPipelineState(MTLRenderCommandEncoder renderCommandEncoder) {
|
||||
var renderPipelineDescriptor = new MTLRenderPipelineDescriptor();
|
||||
|
||||
for (int i = 0; i < EncoderState.MaxColorAttachments; i++)
|
||||
for (int i = 0; i < Constants.MaxColorAttachments; i++)
|
||||
{
|
||||
if (_currentState.RenderTargets[i] != IntPtr.Zero)
|
||||
{
|
||||
|
@ -198,12 +201,7 @@ namespace Ryujinx.Graphics.Metal
|
|||
renderPipelineDescriptor.FragmentFunction = _currentState.FragmentFunction.Value;
|
||||
}
|
||||
|
||||
var error = new NSError(IntPtr.Zero);
|
||||
var pipelineState = _device.NewRenderPipelineState(renderPipelineDescriptor, ref error);
|
||||
if (error != IntPtr.Zero)
|
||||
{
|
||||
Logger.Error?.PrintMsg(LogClass.Gpu, $"Failed to create Render Pipeline State: {StringHelper.String(error.LocalizedDescription)}");
|
||||
}
|
||||
var pipelineState = RenderPipelineCache.GetOrCreate(renderPipelineDescriptor);
|
||||
|
||||
renderCommandEncoder.SetRenderPipelineState(pipelineState);
|
||||
|
||||
|
@ -249,7 +247,7 @@ namespace Ryujinx.Graphics.Metal
|
|||
|
||||
public void UpdateRenderTargets(ITexture[] colors, ITexture depthStencil)
|
||||
{
|
||||
_currentState.RenderTargets = new MTLTexture[EncoderState.MaxColorAttachments];
|
||||
_currentState.RenderTargets = new MTLTexture[Constants.MaxColorAttachments];
|
||||
|
||||
for (int i = 0; i < colors.Length; i++)
|
||||
{
|
||||
|
|
178
src/Ryujinx.Graphics.Metal/StateCache.cs
Normal file
178
src/Ryujinx.Graphics.Metal/StateCache.cs
Normal file
|
@ -0,0 +1,178 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using SharpMetal.Foundation;
|
||||
using SharpMetal.Metal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Ryujinx.Graphics.Metal
|
||||
{
|
||||
[SupportedOSPlatform("macos")]
|
||||
public abstract class StateCache<T, DescriptorT, HashT>
|
||||
{
|
||||
private Dictionary<HashT, T> Cache = new();
|
||||
|
||||
protected abstract HashT GetHash(DescriptorT descriptor);
|
||||
|
||||
protected abstract T CreateValue(DescriptorT descriptor);
|
||||
|
||||
public T GetOrCreate(DescriptorT descriptor)
|
||||
{
|
||||
var hash = GetHash(descriptor);
|
||||
if (Cache.TryGetValue(hash, out T value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
var newValue = CreateValue(descriptor);
|
||||
Cache.Add(hash, newValue);
|
||||
|
||||
return newValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("macos")]
|
||||
public struct RenderPipelineHash
|
||||
{
|
||||
public MTLFunction VertexFunction;
|
||||
public MTLFunction FragmentFunction;
|
||||
public struct ColorAttachmentHash
|
||||
{
|
||||
public MTLPixelFormat PixelFormat;
|
||||
public bool BlendingEnabled;
|
||||
public MTLBlendOperation RgbBlendOperation;
|
||||
public MTLBlendOperation AlphaBlendOperation;
|
||||
public MTLBlendFactor SourceRGBBlendFactor;
|
||||
public MTLBlendFactor DestinationRGBBlendFactor;
|
||||
public MTLBlendFactor SourceAlphaBlendFactor;
|
||||
public MTLBlendFactor DestinationAlphaBlendFactor;
|
||||
}
|
||||
[System.Runtime.CompilerServices.InlineArray(Constants.MaxColorAttachments)]
|
||||
public struct ColorAttachmentHashArray
|
||||
{
|
||||
public ColorAttachmentHash data;
|
||||
}
|
||||
public ColorAttachmentHashArray ColorAttachments;
|
||||
public struct DepthStencilAttachmentHash
|
||||
{
|
||||
public MTLPixelFormat DepthPixelFormat;
|
||||
public MTLPixelFormat StencilPixelFormat;
|
||||
}
|
||||
public DepthStencilAttachmentHash DepthStencilAttachment;
|
||||
public struct VertexDescriptorHash
|
||||
{
|
||||
public struct AttributeHash
|
||||
{
|
||||
public MTLVertexFormat Format;
|
||||
public int Offset;
|
||||
public int BufferIndex;
|
||||
}
|
||||
[System.Runtime.CompilerServices.InlineArray(Constants.MaxVertexAttributes)]
|
||||
public struct AttributeHashArray
|
||||
{
|
||||
public AttributeHash data;
|
||||
}
|
||||
public AttributeHashArray Attributes;
|
||||
public struct LayoutHash
|
||||
{
|
||||
public MTLVertexFormat Format;
|
||||
public int Stride;
|
||||
public int StepFunction;
|
||||
public int StepRate;
|
||||
}
|
||||
[System.Runtime.CompilerServices.InlineArray(Constants.MaxVertexLayouts)]
|
||||
public struct LayoutHashArray
|
||||
{
|
||||
public LayoutHash data;
|
||||
}
|
||||
public LayoutHashArray Layouts;
|
||||
}
|
||||
public VertexDescriptorHash VertexDescriptor;
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("macos")]
|
||||
public class RenderPipelineCache : StateCache<MTLRenderPipelineState, MTLRenderPipelineDescriptor, RenderPipelineHash>
|
||||
{
|
||||
private readonly MTLDevice _device;
|
||||
|
||||
public RenderPipelineCache(MTLDevice device) {
|
||||
_device = device;
|
||||
}
|
||||
|
||||
protected override RenderPipelineHash GetHash(MTLRenderPipelineDescriptor descriptor) {
|
||||
var hash = new RenderPipelineHash();
|
||||
|
||||
// Functions
|
||||
hash.VertexFunction = descriptor.VertexFunction;
|
||||
hash.FragmentFunction = descriptor.FragmentFunction;
|
||||
|
||||
// Color Attachments
|
||||
for (int i = 0; i < Constants.MaxColorAttachments; i++)
|
||||
{
|
||||
var attachment = descriptor.ColorAttachments.Object((ulong)i);
|
||||
hash.ColorAttachments[i] = new RenderPipelineHash.ColorAttachmentHash
|
||||
{
|
||||
PixelFormat = attachment.PixelFormat,
|
||||
BlendingEnabled = attachment.BlendingEnabled,
|
||||
RgbBlendOperation = attachment.RgbBlendOperation,
|
||||
AlphaBlendOperation = attachment.AlphaBlendOperation,
|
||||
SourceRGBBlendFactor = attachment.SourceRGBBlendFactor,
|
||||
DestinationRGBBlendFactor = attachment.DestinationRGBBlendFactor,
|
||||
SourceAlphaBlendFactor = attachment.SourceAlphaBlendFactor,
|
||||
DestinationAlphaBlendFactor = attachment.DestinationAlphaBlendFactor
|
||||
};
|
||||
}
|
||||
|
||||
// Depth stencil attachment
|
||||
hash.DepthStencilAttachment = new RenderPipelineHash.DepthStencilAttachmentHash
|
||||
{
|
||||
DepthPixelFormat = descriptor.DepthAttachmentPixelFormat,
|
||||
StencilPixelFormat = descriptor.StencilAttachmentPixelFormat
|
||||
};
|
||||
|
||||
// Vertex descriptor
|
||||
hash.VertexDescriptor = new RenderPipelineHash.VertexDescriptorHash();
|
||||
|
||||
// Attributes
|
||||
for (int i = 0; i < Constants.MaxVertexAttributes; i++)
|
||||
{
|
||||
var attribute = descriptor.VertexDescriptor.Attributes.Object((ulong)i);
|
||||
hash.VertexDescriptor.Attributes[i] = new RenderPipelineHash.VertexDescriptorHash.AttributeHash
|
||||
{
|
||||
Format = attribute.Format,
|
||||
Offset = (int)attribute.Offset,
|
||||
BufferIndex = (int)attribute.BufferIndex
|
||||
};
|
||||
}
|
||||
|
||||
// Layouts
|
||||
for (int i = 0; i < Constants.MaxVertexLayouts; i++)
|
||||
{
|
||||
var layout = descriptor.VertexDescriptor.Layouts.Object((ulong)i);
|
||||
hash.VertexDescriptor.Layouts[i] = new RenderPipelineHash.VertexDescriptorHash.LayoutHash
|
||||
{
|
||||
Stride = (int)layout.Stride,
|
||||
StepFunction = (int)layout.StepFunction,
|
||||
StepRate = (int)layout.StepRate
|
||||
};
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
protected override MTLRenderPipelineState CreateValue(MTLRenderPipelineDescriptor descriptor)
|
||||
{
|
||||
var error = new NSError(IntPtr.Zero);
|
||||
var pipelineState = _device.NewRenderPipelineState(descriptor, ref error);
|
||||
if (error != IntPtr.Zero)
|
||||
{
|
||||
Logger.Error?.PrintMsg(LogClass.Gpu, $"Failed to create Render Pipeline State: {StringHelper.String(error.LocalizedDescription)}");
|
||||
}
|
||||
|
||||
return pipelineState;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue