From 5fda543f8478222ce80ab3e159fd480de80b2980 Mon Sep 17 00:00:00 2001
From: riperiperi <rhy3756547@hotmail.com>
Date: Fri, 12 May 2023 02:06:15 +0100
Subject: [PATCH] Vulkan: Partially workaround MoltenVK InvalidResource error
 (#4880)

* Add MVK stage flags workaround

* Actually do the workaround

* Remove GS on VS stuff

* Address feedback
---
 .../PipelineLayoutFactory.cs                  | 29 ++++++++++++++++++-
 1 file changed, 28 insertions(+), 1 deletion(-)

diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineLayoutFactory.cs b/src/Ryujinx.Graphics.Vulkan/PipelineLayoutFactory.cs
index 96b3b3b1ca..2d8814191c 100644
--- a/src/Ryujinx.Graphics.Vulkan/PipelineLayoutFactory.cs
+++ b/src/Ryujinx.Graphics.Vulkan/PipelineLayoutFactory.cs
@@ -12,6 +12,28 @@ namespace Ryujinx.Graphics.Vulkan
             ShaderStageFlags.FragmentBit |
             ShaderStageFlags.ComputeBit;
 
+        private static ShaderStageFlags ActiveStages(uint stages)
+        {
+            ShaderStageFlags stageFlags = 0;
+
+            while (stages != 0)
+            {
+                int stage = BitOperations.TrailingZeroCount(stages);
+                stages &= ~(1u << stage);
+
+                stageFlags |= stage switch
+                {
+                    1 => ShaderStageFlags.FragmentBit,
+                    2 => ShaderStageFlags.GeometryBit,
+                    3 => ShaderStageFlags.TessellationControlBit,
+                    4 => ShaderStageFlags.TessellationEvaluationBit,
+                    _ => ShaderStageFlags.VertexBit | ShaderStageFlags.ComputeBit
+                };
+            }
+
+            return stageFlags;
+        }
+
         public static unsafe DescriptorSetLayout[] Create(VulkanRenderer gd, Device device, uint stages, bool usePd, out PipelineLayout layout)
         {
             int stagesCount = BitOperations.PopCount(stages);
@@ -34,6 +56,7 @@ namespace Ryujinx.Graphics.Vulkan
             };
 
             int iter = 0;
+            var activeStages = ActiveStages(stages);
 
             while (stages != 0)
             {
@@ -67,12 +90,16 @@ namespace Ryujinx.Graphics.Vulkan
 
                 void SetStorage(DescriptorSetLayoutBinding* bindings, int maxPerStage, int start = 0)
                 {
+                    // There's a bug on MoltenVK where using the same buffer across different stages
+                    // causes invalid resource errors, allow the binding on all active stages as workaround.
+                    var flags = gd.IsMoltenVk ? activeStages : stageFlags;
+
                     bindings[start + iter] = new DescriptorSetLayoutBinding
                     {
                         Binding = (uint)(start + stage * maxPerStage),
                         DescriptorType = DescriptorType.StorageBuffer,
                         DescriptorCount = (uint)maxPerStage,
-                        StageFlags = stageFlags
+                        StageFlags = flags
                     };
                 }