| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341 |
- using Ryujinx.Common.Logging;
- using Ryujinx.Graphics.GAL;
- using SharpMetal.Foundation;
- using SharpMetal.Metal;
- using System;
- using System.Runtime.Versioning;
- namespace Ryujinx.Graphics.Metal
- {
- [SupportedOSPlatform("macos")]
- struct PipelineState
- {
- public PipelineUid Internal;
- public uint StagesCount
- {
- readonly get => (byte)((Internal.Id0 >> 0) & 0xFF);
- set => Internal.Id0 = (Internal.Id0 & 0xFFFFFFFFFFFFFF00) | ((ulong)value << 0);
- }
- public uint VertexAttributeDescriptionsCount
- {
- readonly get => (byte)((Internal.Id0 >> 8) & 0xFF);
- set => Internal.Id0 = (Internal.Id0 & 0xFFFFFFFFFFFF00FF) | ((ulong)value << 8);
- }
- public uint VertexBindingDescriptionsCount
- {
- readonly get => (byte)((Internal.Id0 >> 16) & 0xFF);
- set => Internal.Id0 = (Internal.Id0 & 0xFFFFFFFFFF00FFFF) | ((ulong)value << 16);
- }
- public uint ColorBlendAttachmentStateCount
- {
- readonly get => (byte)((Internal.Id0 >> 24) & 0xFF);
- set => Internal.Id0 = (Internal.Id0 & 0xFFFFFFFF00FFFFFF) | ((ulong)value << 24);
- }
- /*
- * Can be an input to a pipeline, but not sure what the situation for that is.
- public PrimitiveTopology Topology
- {
- readonly get => (PrimitiveTopology)((Internal.Id6 >> 16) & 0xF);
- set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFFFF0FFFF) | ((ulong)value << 16);
- }
- */
- public MTLLogicOperation LogicOp
- {
- readonly get => (MTLLogicOperation)((Internal.Id0 >> 32) & 0xF);
- set => Internal.Id0 = (Internal.Id0 & 0xFFFFFFF0FFFFFFFF) | ((ulong)value << 32);
- }
- //?
- public bool PrimitiveRestartEnable
- {
- readonly get => ((Internal.Id0 >> 36) & 0x1) != 0UL;
- set => Internal.Id0 = (Internal.Id0 & 0xFFFFFFEFFFFFFFFF) | ((value ? 1UL : 0UL) << 36);
- }
- public bool RasterizerDiscardEnable
- {
- readonly get => ((Internal.Id0 >> 37) & 0x1) != 0UL;
- set => Internal.Id0 = (Internal.Id0 & 0xFFFFFFDFFFFFFFFF) | ((value ? 1UL : 0UL) << 37);
- }
- public bool LogicOpEnable
- {
- readonly get => ((Internal.Id0 >> 38) & 0x1) != 0UL;
- set => Internal.Id0 = (Internal.Id0 & 0xFFFFFFBFFFFFFFFF) | ((value ? 1UL : 0UL) << 38);
- }
- public bool AlphaToCoverageEnable
- {
- readonly get => ((Internal.Id0 >> 40) & 0x1) != 0UL;
- set => Internal.Id0 = (Internal.Id0 & 0xFFFFFEFFFFFFFFFF) | ((value ? 1UL : 0UL) << 40);
- }
- public bool AlphaToOneEnable
- {
- readonly get => ((Internal.Id0 >> 41) & 0x1) != 0UL;
- set => Internal.Id0 = (Internal.Id0 & 0xFFFFFDFFFFFFFFFF) | ((value ? 1UL : 0UL) << 41);
- }
- public MTLPixelFormat DepthStencilFormat
- {
- readonly get => (MTLPixelFormat)(Internal.Id0 >> 48);
- set => Internal.Id0 = (Internal.Id0 & 0x0000FFFFFFFFFFFF) | ((ulong)value << 48);
- }
- // Not sure how to appropriately use this, but it does need to be passed for tess.
- public uint PatchControlPoints
- {
- readonly get => (uint)((Internal.Id1 >> 0) & 0xFFFFFFFF);
- set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFFF00000000) | ((ulong)value << 0);
- }
- public uint SamplesCount
- {
- readonly get => (uint)((Internal.Id1 >> 32) & 0xFFFFFFFF);
- set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFFF) | ((ulong)value << 32);
- }
- // Advanced blend not supported
- private readonly void BuildColorAttachment(MTLRenderPipelineColorAttachmentDescriptor descriptor, ColorBlendStateUid blendState)
- {
- descriptor.PixelFormat = blendState.PixelFormat;
- descriptor.SetBlendingEnabled(blendState.Enable);
- descriptor.AlphaBlendOperation = blendState.AlphaBlendOperation;
- descriptor.RgbBlendOperation = blendState.RgbBlendOperation;
- descriptor.SourceAlphaBlendFactor = blendState.SourceAlphaBlendFactor;
- descriptor.DestinationAlphaBlendFactor = blendState.DestinationAlphaBlendFactor;
- descriptor.SourceRGBBlendFactor = blendState.SourceRGBBlendFactor;
- descriptor.DestinationRGBBlendFactor = blendState.DestinationRGBBlendFactor;
- descriptor.WriteMask = blendState.WriteMask;
- }
- private readonly MTLVertexDescriptor BuildVertexDescriptor()
- {
- MTLVertexDescriptor vertexDescriptor = new();
- for (int i = 0; i < VertexAttributeDescriptionsCount; i++)
- {
- VertexInputAttributeUid uid = Internal.VertexAttributes[i];
- MTLVertexAttributeDescriptor attrib = vertexDescriptor.Attributes.Object((ulong)i);
- attrib.Format = uid.Format;
- attrib.Offset = uid.Offset;
- attrib.BufferIndex = uid.BufferIndex;
- }
- for (int i = 0; i < VertexBindingDescriptionsCount; i++)
- {
- VertexInputLayoutUid uid = Internal.VertexBindings[i];
- MTLVertexBufferLayoutDescriptor layout = vertexDescriptor.Layouts.Object((ulong)i);
- layout.StepFunction = uid.StepFunction;
- layout.StepRate = uid.StepRate;
- layout.Stride = uid.Stride;
- }
- return vertexDescriptor;
- }
- private MTLRenderPipelineDescriptor CreateRenderDescriptor(Program program)
- {
- MTLRenderPipelineDescriptor renderPipelineDescriptor = new();
- for (int i = 0; i < Constants.MaxColorAttachments; i++)
- {
- ColorBlendStateUid blendState = Internal.ColorBlendState[i];
- if (blendState.PixelFormat != MTLPixelFormat.Invalid)
- {
- MTLRenderPipelineColorAttachmentDescriptor pipelineAttachment = renderPipelineDescriptor.ColorAttachments.Object((ulong)i);
- BuildColorAttachment(pipelineAttachment, blendState);
- }
- }
- MTLPixelFormat dsFormat = DepthStencilFormat;
- if (dsFormat != MTLPixelFormat.Invalid)
- {
- switch (dsFormat)
- {
- // Depth Only Attachment
- case MTLPixelFormat.Depth16Unorm:
- case MTLPixelFormat.Depth32Float:
- renderPipelineDescriptor.DepthAttachmentPixelFormat = dsFormat;
- break;
- // Stencil Only Attachment
- case MTLPixelFormat.Stencil8:
- renderPipelineDescriptor.StencilAttachmentPixelFormat = dsFormat;
- break;
- // Combined Attachment
- case MTLPixelFormat.Depth24UnormStencil8:
- case MTLPixelFormat.Depth32FloatStencil8:
- renderPipelineDescriptor.DepthAttachmentPixelFormat = dsFormat;
- renderPipelineDescriptor.StencilAttachmentPixelFormat = dsFormat;
- break;
- default:
- Logger.Error?.PrintMsg(LogClass.Gpu, $"Unsupported Depth/Stencil Format: {dsFormat}!");
- break;
- }
- }
- renderPipelineDescriptor.LogicOperationEnabled = LogicOpEnable;
- renderPipelineDescriptor.LogicOperation = LogicOp;
- renderPipelineDescriptor.AlphaToCoverageEnabled = AlphaToCoverageEnable;
- renderPipelineDescriptor.AlphaToOneEnabled = AlphaToOneEnable;
- renderPipelineDescriptor.RasterizationEnabled = !RasterizerDiscardEnable;
- renderPipelineDescriptor.SampleCount = Math.Max(1, SamplesCount);
- MTLVertexDescriptor vertexDescriptor = BuildVertexDescriptor();
- renderPipelineDescriptor.VertexDescriptor = vertexDescriptor;
- renderPipelineDescriptor.VertexFunction = program.VertexFunction;
- if (program.FragmentFunction.NativePtr != 0)
- {
- renderPipelineDescriptor.FragmentFunction = program.FragmentFunction;
- }
- return renderPipelineDescriptor;
- }
- public MTLRenderPipelineState CreateRenderPipeline(MTLDevice device, Program program)
- {
- if (program.TryGetGraphicsPipeline(ref Internal, out MTLRenderPipelineState pipelineState))
- {
- return pipelineState;
- }
- using MTLRenderPipelineDescriptor descriptor = CreateRenderDescriptor(program);
- NSError error = new(IntPtr.Zero);
- 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)}");
- }
- program.AddGraphicsPipeline(ref Internal, pipelineState);
- return pipelineState;
- }
- public static MTLComputePipelineDescriptor CreateComputeDescriptor(Program program)
- {
- ComputeSize localSize = program.ComputeLocalSize;
- uint maxThreads = (uint)(localSize.X * localSize.Y * localSize.Z);
- if (maxThreads == 0)
- {
- throw new InvalidOperationException($"Local thread size for compute cannot be 0 in any dimension.");
- }
- MTLComputePipelineDescriptor descriptor = new()
- {
- ComputeFunction = program.ComputeFunction,
- MaxTotalThreadsPerThreadgroup = maxThreads,
- ThreadGroupSizeIsMultipleOfThreadExecutionWidth = true,
- };
- return descriptor;
- }
- public static MTLComputePipelineState CreateComputePipeline(MTLDevice device, Program program)
- {
- if (program.TryGetComputePipeline(out MTLComputePipelineState pipelineState))
- {
- return pipelineState;
- }
- using MTLComputePipelineDescriptor descriptor = CreateComputeDescriptor(program);
- NSError error = new(IntPtr.Zero);
- pipelineState = device.NewComputePipelineState(descriptor, MTLPipelineOption.None, 0, ref error);
- if (error != IntPtr.Zero)
- {
- Logger.Error?.PrintMsg(LogClass.Gpu, $"Failed to create Compute Pipeline State: {StringHelper.String(error.LocalizedDescription)}");
- }
- program.AddComputePipeline(pipelineState);
- return pipelineState;
- }
- public void Initialize()
- {
- SamplesCount = 1;
- Internal.ResetColorState();
- }
- /*
- * TODO, this is from vulkan.
- private void UpdateVertexAttributeDescriptions(VulkanRenderer gd)
- {
- // Vertex attributes exceeding the stride are invalid.
- // In metal, they cause glitches with the vertex shader fetching incorrect values.
- // To work around this, we reduce the format to something that doesn't exceed the stride if possible.
- // The assumption is that the exceeding components are not actually accessed on the shader.
- for (int index = 0; index < VertexAttributeDescriptionsCount; index++)
- {
- var attribute = Internal.VertexAttributeDescriptions[index];
- int vbIndex = GetVertexBufferIndex(attribute.Binding);
- if (vbIndex >= 0)
- {
- ref var vb = ref Internal.VertexBindingDescriptions[vbIndex];
- Format format = attribute.Format;
- while (vb.Stride != 0 && attribute.Offset + FormatTable.GetAttributeFormatSize(format) > vb.Stride)
- {
- Format newFormat = FormatTable.DropLastComponent(format);
- if (newFormat == format)
- {
- // That case means we failed to find a format that fits within the stride,
- // so just restore the original format and give up.
- format = attribute.Format;
- break;
- }
- format = newFormat;
- }
- if (attribute.Format != format && gd.FormatCapabilities.BufferFormatSupports(FormatFeatureFlags.VertexBufferBit, format))
- {
- attribute.Format = format;
- }
- }
- _vertexAttributeDescriptions2[index] = attribute;
- }
- }
- private int GetVertexBufferIndex(uint binding)
- {
- for (int index = 0; index < VertexBindingDescriptionsCount; index++)
- {
- if (Internal.VertexBindingDescriptions[index].Binding == binding)
- {
- return index;
- }
- }
- return -1;
- }
- */
- }
- }
|