From 1c6636d3cd01109aa9388dac49c704ed58070be7 Mon Sep 17 00:00:00 2001
From: Isaac Marovitz <isaacryu@icloud.com>
Date: Mon, 30 Sep 2024 17:52:07 +0200
Subject: [PATCH] Make resource encoding less stupid

---
 .../EncoderResources.cs                       |   8 +-
 src/Ryujinx.Graphics.Metal/EncoderState.cs    |   4 +-
 .../EncoderStateManager.cs                    | 105 ++++++++++--------
 3 files changed, 67 insertions(+), 50 deletions(-)

diff --git a/src/Ryujinx.Graphics.Metal/EncoderResources.cs b/src/Ryujinx.Graphics.Metal/EncoderResources.cs
index cfda9bcbe9..562500d767 100644
--- a/src/Ryujinx.Graphics.Metal/EncoderResources.cs
+++ b/src/Ryujinx.Graphics.Metal/EncoderResources.cs
@@ -3,13 +3,13 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Graphics.Metal
 {
-    public struct RenderEncoderResources
+    public struct RenderEncoderBindings
     {
         public List<Resource> Resources = new();
         public List<BufferResource> VertexBuffers = new();
         public List<BufferResource> FragmentBuffers = new();
 
-        public RenderEncoderResources() { }
+        public RenderEncoderBindings() { }
 
         public readonly void Clear()
         {
@@ -19,12 +19,12 @@ namespace Ryujinx.Graphics.Metal
         }
     }
 
-    public struct ComputeEncoderResources
+    public struct ComputeEncoderBindings
     {
         public List<Resource> Resources = new();
         public List<BufferResource> Buffers = new();
 
-        public ComputeEncoderResources() { }
+        public ComputeEncoderBindings() { }
 
         public readonly void Clear()
         {
diff --git a/src/Ryujinx.Graphics.Metal/EncoderState.cs b/src/Ryujinx.Graphics.Metal/EncoderState.cs
index 8aa816efbe..34de168a67 100644
--- a/src/Ryujinx.Graphics.Metal/EncoderState.cs
+++ b/src/Ryujinx.Graphics.Metal/EncoderState.cs
@@ -152,8 +152,8 @@ namespace Ryujinx.Graphics.Metal
         // Only to be used for present
         public bool ClearLoadAction = false;
 
-        public RenderEncoderResources RenderEncoderResources = new();
-        public ComputeEncoderResources ComputeEncoderResources = new();
+        public RenderEncoderBindings RenderEncoderBindings = new();
+        public ComputeEncoderBindings ComputeEncoderBindings = new();
 
         public EncoderState()
         {
diff --git a/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs b/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs
index 13d276af7c..0093ac1486 100644
--- a/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs
+++ b/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs
@@ -5,6 +5,7 @@ using Ryujinx.Graphics.Shader;
 using SharpMetal.Metal;
 using System;
 using System.Linq;
+using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using System.Runtime.Versioning;
 using BufferAssignment = Ryujinx.Graphics.GAL.BufferAssignment;
@@ -191,56 +192,56 @@ namespace Ryujinx.Graphics.Metal
 
         public readonly void RenderResourcesPrepass()
         {
-            _currentState.RenderEncoderResources.Clear();
+            _currentState.RenderEncoderBindings.Clear();
 
             if ((_currentState.Dirty & DirtyFlags.RenderPipeline) != 0)
             {
-                SetVertexBuffers(_currentState.VertexBuffers, ref _currentState.RenderEncoderResources);
+                SetVertexBuffers(_currentState.VertexBuffers, ref _currentState.RenderEncoderBindings);
             }
 
             if ((_currentState.Dirty & DirtyFlags.Uniforms) != 0)
             {
-                UpdateAndBind(_currentState.RenderProgram, Constants.ConstantBuffersSetIndex, ref _currentState.RenderEncoderResources);
+                UpdateAndBind(_currentState.RenderProgram, Constants.ConstantBuffersSetIndex, ref _currentState.RenderEncoderBindings);
             }
 
             if ((_currentState.Dirty & DirtyFlags.Storages) != 0)
             {
-                UpdateAndBind(_currentState.RenderProgram, Constants.StorageBuffersSetIndex, ref _currentState.RenderEncoderResources);
+                UpdateAndBind(_currentState.RenderProgram, Constants.StorageBuffersSetIndex, ref _currentState.RenderEncoderBindings);
             }
 
             if ((_currentState.Dirty & DirtyFlags.Textures) != 0)
             {
-                UpdateAndBind(_currentState.RenderProgram, Constants.TexturesSetIndex, ref _currentState.RenderEncoderResources);
+                UpdateAndBind(_currentState.RenderProgram, Constants.TexturesSetIndex, ref _currentState.RenderEncoderBindings);
             }
 
             if ((_currentState.Dirty & DirtyFlags.Images) != 0)
             {
-                UpdateAndBind(_currentState.RenderProgram, Constants.ImagesSetIndex, ref _currentState.RenderEncoderResources);
+                UpdateAndBind(_currentState.RenderProgram, Constants.ImagesSetIndex, ref _currentState.RenderEncoderBindings);
             }
         }
 
         public readonly void ComputeResourcesPrepass()
         {
-            _currentState.ComputeEncoderResources.Clear();
+            _currentState.ComputeEncoderBindings.Clear();
 
             if ((_currentState.Dirty & DirtyFlags.Uniforms) != 0)
             {
-                UpdateAndBind(_currentState.ComputeProgram, Constants.ConstantBuffersSetIndex, ref _currentState.ComputeEncoderResources);
+                UpdateAndBind(_currentState.ComputeProgram, Constants.ConstantBuffersSetIndex, ref _currentState.ComputeEncoderBindings);
             }
 
             if ((_currentState.Dirty & DirtyFlags.Storages) != 0)
             {
-                UpdateAndBind(_currentState.ComputeProgram, Constants.StorageBuffersSetIndex, ref _currentState.ComputeEncoderResources);
+                UpdateAndBind(_currentState.ComputeProgram, Constants.StorageBuffersSetIndex, ref _currentState.ComputeEncoderBindings);
             }
 
             if ((_currentState.Dirty & DirtyFlags.Textures) != 0)
             {
-                UpdateAndBind(_currentState.ComputeProgram, Constants.TexturesSetIndex, ref _currentState.ComputeEncoderResources);
+                UpdateAndBind(_currentState.ComputeProgram, Constants.TexturesSetIndex, ref _currentState.ComputeEncoderBindings);
             }
 
             if ((_currentState.Dirty & DirtyFlags.Images) != 0)
             {
-                UpdateAndBind(_currentState.ComputeProgram, Constants.ImagesSetIndex, ref _currentState.ComputeEncoderResources);
+                UpdateAndBind(_currentState.ComputeProgram, Constants.ImagesSetIndex, ref _currentState.ComputeEncoderBindings);
             }
         }
 
@@ -291,20 +292,17 @@ namespace Ryujinx.Graphics.Metal
                 SetScissors(renderCommandEncoder);
             }
 
-            foreach (var resource in _currentState.RenderEncoderResources.Resources)
+            foreach (var resource in _currentState.RenderEncoderBindings.Resources)
             {
-                if (resource.MtlResource.NativePtr != IntPtr.Zero)
-                {
-                    renderCommandEncoder.UseResource(resource.MtlResource, resource.ResourceUsage, resource.Stages);
-                }
+                renderCommandEncoder.UseResource(resource.MtlResource, resource.ResourceUsage, resource.Stages);
             }
 
-            foreach (var buffer in _currentState.RenderEncoderResources.VertexBuffers)
+            foreach (var buffer in _currentState.RenderEncoderBindings.VertexBuffers)
             {
                 renderCommandEncoder.SetVertexBuffer(buffer.Buffer, buffer.Offset, buffer.Binding);
             }
 
-            foreach (var buffer in _currentState.RenderEncoderResources.FragmentBuffers)
+            foreach (var buffer in _currentState.RenderEncoderBindings.FragmentBuffers)
             {
                 renderCommandEncoder.SetFragmentBuffer(buffer.Buffer, buffer.Offset, buffer.Binding);
             }
@@ -319,12 +317,12 @@ namespace Ryujinx.Graphics.Metal
                 SetComputePipelineState(computeCommandEncoder);
             }
 
-            foreach (var resource in _currentState.ComputeEncoderResources.Resources)
+            foreach (var resource in _currentState.ComputeEncoderBindings.Resources)
             {
                 computeCommandEncoder.UseResource(resource.MtlResource, resource.ResourceUsage);
             }
 
-            foreach (var buffer in _currentState.ComputeEncoderResources.Buffers)
+            foreach (var buffer in _currentState.ComputeEncoderBindings.Buffers)
             {
                 computeCommandEncoder.SetBuffer(buffer.Buffer, buffer.Offset, buffer.Binding);
             }
@@ -1089,7 +1087,7 @@ namespace Ryujinx.Graphics.Metal
             pipeline.VertexBindingDescriptionsCount = Constants.ZeroBufferIndex + 1; // TODO: move this out?
         }
 
-        private readonly void SetVertexBuffers(VertexBufferState[] bufferStates, ref readonly RenderEncoderResources resources)
+        private readonly void SetVertexBuffers(VertexBufferState[] bufferStates, ref readonly RenderEncoderBindings bindings)
         {
             for (int i = 0; i < bufferStates.Length; i++)
             {
@@ -1097,7 +1095,7 @@ namespace Ryujinx.Graphics.Metal
 
                 if (mtlBuffer.NativePtr != IntPtr.Zero)
                 {
-                    resources.VertexBuffers.Add(new BufferResource(mtlBuffer, (ulong)offset, (ulong)i));
+                    bindings.VertexBuffers.Add(new BufferResource(mtlBuffer, (ulong)offset, (ulong)i));
                 }
             }
 
@@ -1111,7 +1109,7 @@ namespace Ryujinx.Graphics.Metal
             }
 
             var zeroMtlBuffer = autoZeroBuffer.Get(_pipeline.Cbs).Value;
-            resources.VertexBuffers.Add(new BufferResource(zeroMtlBuffer, 0, Constants.ZeroBufferIndex));
+            bindings.VertexBuffers.Add(new BufferResource(zeroMtlBuffer, 0, Constants.ZeroBufferIndex));
         }
 
         private readonly (ulong gpuAddress, IntPtr nativePtr) AddressForBuffer(ref BufferRef buffer)
@@ -1203,7 +1201,25 @@ namespace Ryujinx.Graphics.Metal
             return (gpuAddress, nativePtr);
         }
 
-        private readonly void UpdateAndBind(Program program, uint setIndex, ref readonly RenderEncoderResources resources)
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        private static void AddResource(IntPtr resourcePointer, MTLResourceUsage usage, MTLRenderStages stages, ref readonly RenderEncoderBindings bindings)
+        {
+            if (resourcePointer != IntPtr.Zero)
+            {
+                bindings.Resources.Add(new Resource(new MTLResource(resourcePointer), usage, stages));
+            }
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        private static void AddResource(IntPtr resourcePointer, MTLResourceUsage usage, ref readonly ComputeEncoderBindings bindings)
+        {
+            if (resourcePointer != IntPtr.Zero)
+            {
+                bindings.Resources.Add(new Resource(new MTLResource(resourcePointer), usage, 0));
+            }
+        }
+
+        private readonly void UpdateAndBind(Program program, uint setIndex, ref readonly RenderEncoderBindings bindings)
         {
             var bindingSegments = program.BindingSegments[setIndex];
 
@@ -1264,7 +1280,7 @@ namespace Ryujinx.Graphics.Metal
                                 renderStages |= MTLRenderStages.RenderStageFragment;
                             }
 
-                            resources.Resources.Add(new Resource(new MTLResource(nativePtr), MTLResourceUsage.Read, renderStages));
+                            AddResource(nativePtr, MTLResourceUsage.Read, renderStages, in bindings);
                         }
                         break;
                     case Constants.StorageBuffersSetIndex:
@@ -1293,7 +1309,7 @@ namespace Ryujinx.Graphics.Metal
                                 renderStages |= MTLRenderStages.RenderStageFragment;
                             }
 
-                            resources.Resources.Add(new Resource(new MTLResource(nativePtr), MTLResourceUsage.Read, renderStages));
+                            AddResource(nativePtr, MTLResourceUsage.Read, renderStages, in bindings);
                         }
                         break;
                     case Constants.TexturesSetIndex:
@@ -1336,7 +1352,7 @@ namespace Ryujinx.Graphics.Metal
                                     renderStages |= MTLRenderStages.RenderStageFragment;
                                 }
 
-                                resources.Resources.Add(new Resource(new MTLResource(nativePtr), MTLResourceUsage.Read, renderStages));
+                                AddResource(nativePtr, MTLResourceUsage.Read, renderStages, in bindings);
                             }
                         }
                         else
@@ -1373,7 +1389,7 @@ namespace Ryujinx.Graphics.Metal
                                         renderStages |= MTLRenderStages.RenderStageFragment;
                                     }
 
-                                    resources.Resources.Add(new Resource(new MTLResource(nativePtr), MTLResourceUsage.Read, renderStages));
+                                    AddResource(nativePtr, MTLResourceUsage.Read, renderStages, in bindings);
                                 }
 
                                 foreach (var sampler in samplers)
@@ -1425,7 +1441,7 @@ namespace Ryujinx.Graphics.Metal
                                         renderStages |= MTLRenderStages.RenderStageFragment;
                                     }
 
-                                    resources.Resources.Add(new Resource(new MTLResource(nativePtr), MTLResourceUsage.Read, renderStages));
+                                    AddResource(nativePtr, MTLResourceUsage.Read, renderStages, in bindings);
                                 }
                             }
                         }
@@ -1456,7 +1472,7 @@ namespace Ryujinx.Graphics.Metal
                                     renderStages |= MTLRenderStages.RenderStageFragment;
                                 }
 
-                                resources.Resources.Add(new Resource(new MTLResource(nativePtr), MTLResourceUsage.Read | MTLResourceUsage.Write, renderStages));
+                                AddResource(nativePtr, MTLResourceUsage.Read | MTLResourceUsage.Write, renderStages, in bindings);
                             }
                         }
                         else
@@ -1488,7 +1504,7 @@ namespace Ryujinx.Graphics.Metal
                                         renderStages |= MTLRenderStages.RenderStageFragment;
                                     }
 
-                                    resources.Resources.Add(new Resource(new MTLResource(nativePtr), MTLResourceUsage.Read | MTLResourceUsage.Write, renderStages));
+                                    AddResource(nativePtr, MTLResourceUsage.Read | MTLResourceUsage.Write, renderStages, in bindings);
                                 }
                             }
                             else
@@ -1516,7 +1532,7 @@ namespace Ryujinx.Graphics.Metal
                                         renderStages |= MTLRenderStages.RenderStageFragment;
                                     }
 
-                                    resources.Resources.Add(new Resource(new MTLResource(nativePtr), MTLResourceUsage.Read | MTLResourceUsage.Write, renderStages));
+                                    AddResource(nativePtr, MTLResourceUsage.Read | MTLResourceUsage.Write, renderStages, in bindings);
                                 }
                             }
                         }
@@ -1528,18 +1544,18 @@ namespace Ryujinx.Graphics.Metal
             {
                 vertArgBuffer.Holder.SetDataUnchecked(vertArgBuffer.Offset, MemoryMarshal.AsBytes(vertResourceIds));
                 var mtlVertArgBuffer = _bufferManager.GetBuffer(vertArgBuffer.Handle, false).Get(_pipeline.Cbs).Value;
-                resources.VertexBuffers.Add(new BufferResource(mtlVertArgBuffer, (uint)vertArgBuffer.Range.Offset, SetIndexToBindingIndex(setIndex)));
+                bindings.VertexBuffers.Add(new BufferResource(mtlVertArgBuffer, (uint)vertArgBuffer.Range.Offset, SetIndexToBindingIndex(setIndex)));
             }
 
             if (program.FragArgumentBufferSizes[setIndex] > 0)
             {
                 fragArgBuffer.Holder.SetDataUnchecked(fragArgBuffer.Offset, MemoryMarshal.AsBytes(fragResourceIds));
                 var mtlFragArgBuffer = _bufferManager.GetBuffer(fragArgBuffer.Handle, false).Get(_pipeline.Cbs).Value;
-                resources.FragmentBuffers.Add(new BufferResource(mtlFragArgBuffer, (uint)fragArgBuffer.Range.Offset, SetIndexToBindingIndex(setIndex)));
+                bindings.FragmentBuffers.Add(new BufferResource(mtlFragArgBuffer, (uint)fragArgBuffer.Range.Offset, SetIndexToBindingIndex(setIndex)));
             }
         }
 
-        private readonly void UpdateAndBind(Program program, uint setIndex, ref readonly ComputeEncoderResources resources)
+        private readonly void UpdateAndBind(Program program, uint setIndex, ref readonly ComputeEncoderBindings bindings)
         {
             var bindingSegments = program.BindingSegments[setIndex];
 
@@ -1575,7 +1591,8 @@ namespace Ryujinx.Graphics.Metal
 
                             if ((segment.Stages & ResourceStages.Compute) != 0)
                             {
-                                resources.Resources.Add(new Resource(new MTLResource(nativePtr), MTLResourceUsage.Read, 0));
+                                AddResource(nativePtr, MTLResourceUsage.Read, in bindings);
+                                bindings.Resources.Add(new Resource(new MTLResource(nativePtr), MTLResourceUsage.Read, 0));
                                 resourceIds[resourceIdIndex] = gpuAddress;
                                 resourceIdIndex++;
                             }
@@ -1591,7 +1608,7 @@ namespace Ryujinx.Graphics.Metal
 
                             if ((segment.Stages & ResourceStages.Compute) != 0)
                             {
-                                resources.Resources.Add(new Resource(new MTLResource(nativePtr), MTLResourceUsage.Read | MTLResourceUsage.Write, 0));
+                                AddResource(nativePtr, MTLResourceUsage.Read | MTLResourceUsage.Write, in bindings);
                                 resourceIds[resourceIdIndex] = gpuAddress;
                                 resourceIdIndex++;
                             }
@@ -1609,7 +1626,7 @@ namespace Ryujinx.Graphics.Metal
 
                                 if ((segment.Stages & ResourceStages.Compute) != 0)
                                 {
-                                    resources.Resources.Add(new Resource(new MTLResource(nativePtr), MTLResourceUsage.Read, 0));
+                                    AddResource(nativePtr, MTLResourceUsage.Read, in bindings);
                                     resourceIds[resourceIdIndex] = gpuAddress;
                                     resourceIdIndex++;
 
@@ -1637,7 +1654,7 @@ namespace Ryujinx.Graphics.Metal
 
                                     if ((segment.Stages & ResourceStages.Compute) != 0)
                                     {
-                                        resources.Resources.Add(new Resource(new MTLResource(nativePtr), MTLResourceUsage.Read, 0));
+                                        AddResource(nativePtr, MTLResourceUsage.Read, in bindings);
                                         resourceIds[resourceIdIndex] = gpuAddress;
                                         resourceIdIndex++;
 
@@ -1665,7 +1682,7 @@ namespace Ryujinx.Graphics.Metal
 
                                     if ((segment.Stages & ResourceStages.Compute) != 0)
                                     {
-                                        resources.Resources.Add(new Resource(new MTLResource(nativePtr), MTLResourceUsage.Read, 0));
+                                        AddResource(nativePtr, MTLResourceUsage.Read, in bindings);
                                         resourceIds[resourceIdIndex] = gpuAddress;
                                         resourceIdIndex++;
                                     }
@@ -1685,7 +1702,7 @@ namespace Ryujinx.Graphics.Metal
 
                                 if ((segment.Stages & ResourceStages.Compute) != 0)
                                 {
-                                    resources.Resources.Add(new Resource(new MTLResource(nativePtr), MTLResourceUsage.Read | MTLResourceUsage.Write, 0));
+                                    AddResource(nativePtr, MTLResourceUsage.Read | MTLResourceUsage.Write, in bindings);
                                     resourceIds[resourceIdIndex] = gpuAddress;
                                     resourceIdIndex++;
                                 }
@@ -1706,7 +1723,7 @@ namespace Ryujinx.Graphics.Metal
 
                                     if ((segment.Stages & ResourceStages.Compute) != 0)
                                     {
-                                        resources.Resources.Add(new Resource(new MTLResource(nativePtr), MTLResourceUsage.Read | MTLResourceUsage.Write, 0));
+                                        AddResource(nativePtr, MTLResourceUsage.Read | MTLResourceUsage.Write, in bindings);
                                         resourceIds[resourceIdIndex] = gpuAddress;
                                         resourceIdIndex++;
                                     }
@@ -1723,7 +1740,7 @@ namespace Ryujinx.Graphics.Metal
 
                                     if ((segment.Stages & ResourceStages.Compute) != 0)
                                     {
-                                        resources.Resources.Add(new Resource(new MTLResource(nativePtr), MTLResourceUsage.Read | MTLResourceUsage.Write, 0));
+                                        AddResource(nativePtr, MTLResourceUsage.Read | MTLResourceUsage.Write, in bindings);
                                         resourceIds[resourceIdIndex] = gpuAddress;
                                         resourceIdIndex++;
                                     }
@@ -1738,7 +1755,7 @@ namespace Ryujinx.Graphics.Metal
             {
                 argBuffer.Holder.SetDataUnchecked(argBuffer.Offset, MemoryMarshal.AsBytes(resourceIds));
                 var mtlArgBuffer = _bufferManager.GetBuffer(argBuffer.Handle, false).Get(_pipeline.Cbs).Value;
-                resources.Buffers.Add(new BufferResource(mtlArgBuffer, (uint)argBuffer.Range.Offset, SetIndexToBindingIndex(setIndex)));
+                bindings.Buffers.Add(new BufferResource(mtlArgBuffer, (uint)argBuffer.Range.Offset, SetIndexToBindingIndex(setIndex)));
             }
         }