From 5fda543f8478222ce80ab3e159fd480de80b2980 Mon Sep 17 00:00:00 2001 From: riperiperi 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 96b3b3b1c..2d8814191 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 }; }