aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Vulkan/PipelineLayoutFactory.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.Graphics.Vulkan/PipelineLayoutFactory.cs')
-rw-r--r--src/Ryujinx.Graphics.Vulkan/PipelineLayoutFactory.cs271
1 files changed, 44 insertions, 227 deletions
diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineLayoutFactory.cs b/src/Ryujinx.Graphics.Vulkan/PipelineLayoutFactory.cs
index 2d881419..bcb2c1a5 100644
--- a/src/Ryujinx.Graphics.Vulkan/PipelineLayoutFactory.cs
+++ b/src/Ryujinx.Graphics.Vulkan/PipelineLayoutFactory.cs
@@ -1,257 +1,74 @@
using Ryujinx.Graphics.GAL;
using Silk.NET.Vulkan;
-using System.Collections.Generic;
-using System.Numerics;
+using System.Collections.ObjectModel;
namespace Ryujinx.Graphics.Vulkan
{
static class PipelineLayoutFactory
{
- private const ShaderStageFlags SupportBufferStages =
- ShaderStageFlags.VertexBit |
- 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)
+ public static unsafe (DescriptorSetLayout[], PipelineLayout) Create(
+ VulkanRenderer gd,
+ Device device,
+ ReadOnlyCollection<ResourceDescriptorCollection> setDescriptors,
+ bool usePushDescriptors)
{
- int stagesCount = BitOperations.PopCount(stages);
-
- int uCount = Constants.MaxUniformBuffersPerStage * stagesCount + 1;
- int tCount = Constants.MaxTexturesPerStage * 2 * stagesCount;
- int iCount = Constants.MaxImagesPerStage * 2 * stagesCount;
+ DescriptorSetLayout[] layouts = new DescriptorSetLayout[setDescriptors.Count];
- DescriptorSetLayoutBinding* uLayoutBindings = stackalloc DescriptorSetLayoutBinding[uCount];
- DescriptorSetLayoutBinding* sLayoutBindings = stackalloc DescriptorSetLayoutBinding[stagesCount];
- DescriptorSetLayoutBinding* tLayoutBindings = stackalloc DescriptorSetLayoutBinding[tCount];
- DescriptorSetLayoutBinding* iLayoutBindings = stackalloc DescriptorSetLayoutBinding[iCount];
+ bool isMoltenVk = gd.IsMoltenVk;
- uLayoutBindings[0] = new DescriptorSetLayoutBinding
+ for (int setIndex = 0; setIndex < setDescriptors.Count; setIndex++)
{
- Binding = 0,
- DescriptorType = DescriptorType.UniformBuffer,
- DescriptorCount = 1,
- StageFlags = SupportBufferStages
- };
+ ResourceDescriptorCollection rdc = setDescriptors[setIndex];
- int iter = 0;
- var activeStages = ActiveStages(stages);
-
- while (stages != 0)
- {
- int stage = BitOperations.TrailingZeroCount(stages);
- stages &= ~(1u << stage);
+ ResourceStages activeStages = ResourceStages.None;
- var stageFlags = stage switch
+ if (isMoltenVk)
{
- 1 => ShaderStageFlags.FragmentBit,
- 2 => ShaderStageFlags.GeometryBit,
- 3 => ShaderStageFlags.TessellationControlBit,
- 4 => ShaderStageFlags.TessellationEvaluationBit,
- _ => ShaderStageFlags.VertexBit | ShaderStageFlags.ComputeBit
- };
-
- void Set(DescriptorSetLayoutBinding* bindings, int maxPerStage, DescriptorType type, int start, int skip)
- {
- int totalPerStage = maxPerStage * skip;
-
- for (int i = 0; i < maxPerStage; i++)
+ for (int descIndex = 0; descIndex < rdc.Descriptors.Count; descIndex++)
{
- bindings[start + iter * totalPerStage + i] = new DescriptorSetLayoutBinding
- {
- Binding = (uint)(start + stage * totalPerStage + i),
- DescriptorType = type,
- DescriptorCount = 1,
- StageFlags = stageFlags
- };
+ activeStages |= rdc.Descriptors[descIndex].Stages;
}
}
- 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 = flags
- };
- }
-
- Set(uLayoutBindings, Constants.MaxUniformBuffersPerStage, DescriptorType.UniformBuffer, 1, 1);
- SetStorage(sLayoutBindings, Constants.MaxStorageBuffersPerStage);
- Set(tLayoutBindings, Constants.MaxTexturesPerStage, DescriptorType.CombinedImageSampler, 0, 2);
- Set(tLayoutBindings, Constants.MaxTexturesPerStage, DescriptorType.UniformTexelBuffer, Constants.MaxTexturesPerStage, 2);
- Set(iLayoutBindings, Constants.MaxImagesPerStage, DescriptorType.StorageImage, 0, 2);
- Set(iLayoutBindings, Constants.MaxImagesPerStage, DescriptorType.StorageTexelBuffer, Constants.MaxImagesPerStage, 2);
-
- iter++;
- }
-
- DescriptorSetLayout[] layouts = new DescriptorSetLayout[PipelineBase.DescriptorSetLayouts];
-
- var uDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()
- {
- SType = StructureType.DescriptorSetLayoutCreateInfo,
- PBindings = uLayoutBindings,
- BindingCount = (uint)uCount,
- Flags = usePd ? DescriptorSetLayoutCreateFlags.PushDescriptorBitKhr : 0
- };
-
- var sDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()
- {
- SType = StructureType.DescriptorSetLayoutCreateInfo,
- PBindings = sLayoutBindings,
- BindingCount = (uint)stagesCount
- };
-
- var tDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()
- {
- SType = StructureType.DescriptorSetLayoutCreateInfo,
- PBindings = tLayoutBindings,
- BindingCount = (uint)tCount
- };
-
- var iDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()
- {
- SType = StructureType.DescriptorSetLayoutCreateInfo,
- PBindings = iLayoutBindings,
- BindingCount = (uint)iCount
- };
-
- gd.Api.CreateDescriptorSetLayout(device, uDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.UniformSetIndex]).ThrowOnError();
- gd.Api.CreateDescriptorSetLayout(device, sDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.StorageSetIndex]).ThrowOnError();
- gd.Api.CreateDescriptorSetLayout(device, tDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.TextureSetIndex]).ThrowOnError();
- gd.Api.CreateDescriptorSetLayout(device, iDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.ImageSetIndex]).ThrowOnError();
+ DescriptorSetLayoutBinding[] layoutBindings = new DescriptorSetLayoutBinding[rdc.Descriptors.Count];
- fixed (DescriptorSetLayout* pLayouts = layouts)
- {
- var pipelineLayoutCreateInfo = new PipelineLayoutCreateInfo()
+ for (int descIndex = 0; descIndex < rdc.Descriptors.Count; descIndex++)
{
- SType = StructureType.PipelineLayoutCreateInfo,
- PSetLayouts = pLayouts,
- SetLayoutCount = PipelineBase.DescriptorSetLayouts
- };
-
- gd.Api.CreatePipelineLayout(device, &pipelineLayoutCreateInfo, null, out layout).ThrowOnError();
- }
+ ResourceDescriptor descriptor = rdc.Descriptors[descIndex];
- return layouts;
- }
-
- public static unsafe DescriptorSetLayout[] CreateMinimal(VulkanRenderer gd, Device device, ShaderSource[] shaders, out PipelineLayout layout)
- {
- int stagesCount = shaders.Length;
+ ResourceStages stages = descriptor.Stages;
- int uCount = 0;
- int sCount = 0;
- int tCount = 0;
- int iCount = 0;
-
- foreach (var shader in shaders)
- {
- uCount += shader.Bindings.UniformBufferBindings.Count;
- sCount += shader.Bindings.StorageBufferBindings.Count;
- tCount += shader.Bindings.TextureBindings.Count;
- iCount += shader.Bindings.ImageBindings.Count;
- }
-
- DescriptorSetLayoutBinding* uLayoutBindings = stackalloc DescriptorSetLayoutBinding[uCount];
- DescriptorSetLayoutBinding* sLayoutBindings = stackalloc DescriptorSetLayoutBinding[sCount];
- DescriptorSetLayoutBinding* tLayoutBindings = stackalloc DescriptorSetLayoutBinding[tCount];
- DescriptorSetLayoutBinding* iLayoutBindings = stackalloc DescriptorSetLayoutBinding[iCount];
-
- int uIndex = 0;
- int sIndex = 0;
- int tIndex = 0;
- int iIndex = 0;
+ if (descriptor.Type == ResourceType.StorageBuffer && isMoltenVk)
+ {
+ // 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.
+ stages = activeStages;
+ }
- foreach (var shader in shaders)
- {
- var stageFlags = shader.Stage.Convert();
+ layoutBindings[descIndex] = new DescriptorSetLayoutBinding()
+ {
+ Binding = (uint)descriptor.Binding,
+ DescriptorType = descriptor.Type.Convert(),
+ DescriptorCount = (uint)descriptor.Count,
+ StageFlags = stages.Convert()
+ };
+ }
- void Set(DescriptorSetLayoutBinding* bindings, DescriptorType type, ref int start, IEnumerable<int> bds)
+ fixed (DescriptorSetLayoutBinding* pLayoutBindings = layoutBindings)
{
- foreach (var b in bds)
+ var descriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()
{
- bindings[start++] = new DescriptorSetLayoutBinding
- {
- Binding = (uint)b,
- DescriptorType = type,
- DescriptorCount = 1,
- StageFlags = stageFlags
- };
- }
- }
+ SType = StructureType.DescriptorSetLayoutCreateInfo,
+ PBindings = pLayoutBindings,
+ BindingCount = (uint)layoutBindings.Length,
+ Flags = usePushDescriptors && setIndex == 0 ? DescriptorSetLayoutCreateFlags.PushDescriptorBitKhr : DescriptorSetLayoutCreateFlags.None
+ };
- // TODO: Support buffer textures and images here.
- // This is only used for the helper shaders on the backend, and we don't use buffer textures on them
- // so far, so it's not really necessary right now.
- Set(uLayoutBindings, DescriptorType.UniformBuffer, ref uIndex, shader.Bindings.UniformBufferBindings);
- Set(sLayoutBindings, DescriptorType.StorageBuffer, ref sIndex, shader.Bindings.StorageBufferBindings);
- Set(tLayoutBindings, DescriptorType.CombinedImageSampler, ref tIndex, shader.Bindings.TextureBindings);
- Set(iLayoutBindings, DescriptorType.StorageImage, ref iIndex, shader.Bindings.ImageBindings);
+ gd.Api.CreateDescriptorSetLayout(device, descriptorSetLayoutCreateInfo, null, out layouts[setIndex]).ThrowOnError();
+ }
}
- DescriptorSetLayout[] layouts = new DescriptorSetLayout[PipelineBase.DescriptorSetLayouts];
-
- var uDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()
- {
- SType = StructureType.DescriptorSetLayoutCreateInfo,
- PBindings = uLayoutBindings,
- BindingCount = (uint)uCount
- };
-
- var sDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()
- {
- SType = StructureType.DescriptorSetLayoutCreateInfo,
- PBindings = sLayoutBindings,
- BindingCount = (uint)sCount
- };
-
- var tDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()
- {
- SType = StructureType.DescriptorSetLayoutCreateInfo,
- PBindings = tLayoutBindings,
- BindingCount = (uint)tCount
- };
-
- var iDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()
- {
- SType = StructureType.DescriptorSetLayoutCreateInfo,
- PBindings = iLayoutBindings,
- BindingCount = (uint)iCount
- };
-
- gd.Api.CreateDescriptorSetLayout(device, uDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.UniformSetIndex]).ThrowOnError();
- gd.Api.CreateDescriptorSetLayout(device, sDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.StorageSetIndex]).ThrowOnError();
- gd.Api.CreateDescriptorSetLayout(device, tDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.TextureSetIndex]).ThrowOnError();
- gd.Api.CreateDescriptorSetLayout(device, iDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.ImageSetIndex]).ThrowOnError();
+ PipelineLayout layout;
fixed (DescriptorSetLayout* pLayouts = layouts)
{
@@ -259,13 +76,13 @@ namespace Ryujinx.Graphics.Vulkan
{
SType = StructureType.PipelineLayoutCreateInfo,
PSetLayouts = pLayouts,
- SetLayoutCount = PipelineBase.DescriptorSetLayouts
+ SetLayoutCount = (uint)layouts.Length
};
gd.Api.CreatePipelineLayout(device, &pipelineLayoutCreateInfo, null, out layout).ThrowOnError();
}
- return layouts;
+ return (layouts, layout);
}
}
}