PipelineLayoutFactory.cs
1 using Ryujinx.Common.Memory; 2 using Ryujinx.Graphics.GAL; 3 using Silk.NET.Vulkan; 4 using System; 5 using System.Collections.ObjectModel; 6 7 namespace Ryujinx.Graphics.Vulkan 8 { 9 record struct ResourceLayouts(DescriptorSetLayout[] DescriptorSetLayouts, bool[] DescriptorSetLayoutsUpdateAfterBind, PipelineLayout PipelineLayout); 10 11 static class PipelineLayoutFactory 12 { 13 public static unsafe ResourceLayouts Create( 14 VulkanRenderer gd, 15 Device device, 16 ReadOnlyCollection<ResourceDescriptorCollection> setDescriptors, 17 bool usePushDescriptors) 18 { 19 DescriptorSetLayout[] layouts = new DescriptorSetLayout[setDescriptors.Count]; 20 bool[] updateAfterBindFlags = new bool[setDescriptors.Count]; 21 22 bool isMoltenVk = gd.IsMoltenVk; 23 24 for (int setIndex = 0; setIndex < setDescriptors.Count; setIndex++) 25 { 26 ResourceDescriptorCollection rdc = setDescriptors[setIndex]; 27 28 ResourceStages activeStages = ResourceStages.None; 29 30 if (isMoltenVk) 31 { 32 for (int descIndex = 0; descIndex < rdc.Descriptors.Count; descIndex++) 33 { 34 activeStages |= rdc.Descriptors[descIndex].Stages; 35 } 36 } 37 38 DescriptorSetLayoutBinding[] layoutBindings = new DescriptorSetLayoutBinding[rdc.Descriptors.Count]; 39 40 bool hasArray = false; 41 42 for (int descIndex = 0; descIndex < rdc.Descriptors.Count; descIndex++) 43 { 44 ResourceDescriptor descriptor = rdc.Descriptors[descIndex]; 45 ResourceStages stages = descriptor.Stages; 46 47 if (descriptor.Type == ResourceType.StorageBuffer && isMoltenVk) 48 { 49 // There's a bug on MoltenVK where using the same buffer across different stages 50 // causes invalid resource errors, allow the binding on all active stages as workaround. 51 stages = activeStages; 52 } 53 54 layoutBindings[descIndex] = new DescriptorSetLayoutBinding 55 { 56 Binding = (uint)descriptor.Binding, 57 DescriptorType = descriptor.Type.Convert(), 58 DescriptorCount = (uint)descriptor.Count, 59 StageFlags = stages.Convert(), 60 }; 61 62 if (descriptor.Count > 1) 63 { 64 hasArray = true; 65 } 66 } 67 68 fixed (DescriptorSetLayoutBinding* pLayoutBindings = layoutBindings) 69 { 70 DescriptorSetLayoutCreateFlags flags = DescriptorSetLayoutCreateFlags.None; 71 72 if (usePushDescriptors && setIndex == 0) 73 { 74 flags = DescriptorSetLayoutCreateFlags.PushDescriptorBitKhr; 75 } 76 77 if (gd.Vendor == Vendor.Intel && hasArray) 78 { 79 // Some vendors (like Intel) have low per-stage limits. 80 // We must set the flag if we exceed those limits. 81 flags |= DescriptorSetLayoutCreateFlags.UpdateAfterBindPoolBit; 82 83 updateAfterBindFlags[setIndex] = true; 84 } 85 86 var descriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo 87 { 88 SType = StructureType.DescriptorSetLayoutCreateInfo, 89 PBindings = pLayoutBindings, 90 BindingCount = (uint)layoutBindings.Length, 91 Flags = flags, 92 }; 93 94 gd.Api.CreateDescriptorSetLayout(device, in descriptorSetLayoutCreateInfo, null, out layouts[setIndex]).ThrowOnError(); 95 } 96 } 97 98 PipelineLayout layout; 99 100 fixed (DescriptorSetLayout* pLayouts = layouts) 101 { 102 var pipelineLayoutCreateInfo = new PipelineLayoutCreateInfo 103 { 104 SType = StructureType.PipelineLayoutCreateInfo, 105 PSetLayouts = pLayouts, 106 SetLayoutCount = (uint)layouts.Length, 107 }; 108 109 gd.Api.CreatePipelineLayout(device, &pipelineLayoutCreateInfo, null, out layout).ThrowOnError(); 110 } 111 112 return new ResourceLayouts(layouts, updateAfterBindFlags, layout); 113 } 114 } 115 }