/ src / Ryujinx.Graphics.Vulkan / PipelineLayoutFactory.cs
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  }