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.cs244
1 files changed, 244 insertions, 0 deletions
diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineLayoutFactory.cs b/src/Ryujinx.Graphics.Vulkan/PipelineLayoutFactory.cs
new file mode 100644
index 00000000..96b3b3b1
--- /dev/null
+++ b/src/Ryujinx.Graphics.Vulkan/PipelineLayoutFactory.cs
@@ -0,0 +1,244 @@
+using Ryujinx.Graphics.GAL;
+using Silk.NET.Vulkan;
+using System.Collections.Generic;
+using System.Numerics;
+
+namespace Ryujinx.Graphics.Vulkan
+{
+ static class PipelineLayoutFactory
+ {
+ private const ShaderStageFlags SupportBufferStages =
+ ShaderStageFlags.VertexBit |
+ ShaderStageFlags.FragmentBit |
+ ShaderStageFlags.ComputeBit;
+
+ public static unsafe DescriptorSetLayout[] Create(VulkanRenderer gd, Device device, uint stages, bool usePd, out PipelineLayout layout)
+ {
+ int stagesCount = BitOperations.PopCount(stages);
+
+ int uCount = Constants.MaxUniformBuffersPerStage * stagesCount + 1;
+ int tCount = Constants.MaxTexturesPerStage * 2 * stagesCount;
+ int iCount = Constants.MaxImagesPerStage * 2 * stagesCount;
+
+ DescriptorSetLayoutBinding* uLayoutBindings = stackalloc DescriptorSetLayoutBinding[uCount];
+ DescriptorSetLayoutBinding* sLayoutBindings = stackalloc DescriptorSetLayoutBinding[stagesCount];
+ DescriptorSetLayoutBinding* tLayoutBindings = stackalloc DescriptorSetLayoutBinding[tCount];
+ DescriptorSetLayoutBinding* iLayoutBindings = stackalloc DescriptorSetLayoutBinding[iCount];
+
+ uLayoutBindings[0] = new DescriptorSetLayoutBinding
+ {
+ Binding = 0,
+ DescriptorType = DescriptorType.UniformBuffer,
+ DescriptorCount = 1,
+ StageFlags = SupportBufferStages
+ };
+
+ int iter = 0;
+
+ while (stages != 0)
+ {
+ int stage = BitOperations.TrailingZeroCount(stages);
+ stages &= ~(1u << stage);
+
+ var stageFlags = stage switch
+ {
+ 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++)
+ {
+ bindings[start + iter * totalPerStage + i] = new DescriptorSetLayoutBinding
+ {
+ Binding = (uint)(start + stage * totalPerStage + i),
+ DescriptorType = type,
+ DescriptorCount = 1,
+ StageFlags = stageFlags
+ };
+ }
+ }
+
+ void SetStorage(DescriptorSetLayoutBinding* bindings, int maxPerStage, int start = 0)
+ {
+ bindings[start + iter] = new DescriptorSetLayoutBinding
+ {
+ Binding = (uint)(start + stage * maxPerStage),
+ DescriptorType = DescriptorType.StorageBuffer,
+ DescriptorCount = (uint)maxPerStage,
+ StageFlags = stageFlags
+ };
+ }
+
+ 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();
+
+ fixed (DescriptorSetLayout* pLayouts = layouts)
+ {
+ var pipelineLayoutCreateInfo = new PipelineLayoutCreateInfo()
+ {
+ SType = StructureType.PipelineLayoutCreateInfo,
+ PSetLayouts = pLayouts,
+ SetLayoutCount = PipelineBase.DescriptorSetLayouts
+ };
+
+ gd.Api.CreatePipelineLayout(device, &pipelineLayoutCreateInfo, null, out layout).ThrowOnError();
+ }
+
+ return layouts;
+ }
+
+ public static unsafe DescriptorSetLayout[] CreateMinimal(VulkanRenderer gd, Device device, ShaderSource[] shaders, out PipelineLayout layout)
+ {
+ int stagesCount = shaders.Length;
+
+ 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;
+
+ foreach (var shader in shaders)
+ {
+ var stageFlags = shader.Stage.Convert();
+
+ void Set(DescriptorSetLayoutBinding* bindings, DescriptorType type, ref int start, IEnumerable<int> bds)
+ {
+ foreach (var b in bds)
+ {
+ bindings[start++] = new DescriptorSetLayoutBinding
+ {
+ Binding = (uint)b,
+ DescriptorType = type,
+ DescriptorCount = 1,
+ StageFlags = stageFlags
+ };
+ }
+ }
+
+ // 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);
+ }
+
+ 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();
+
+ fixed (DescriptorSetLayout* pLayouts = layouts)
+ {
+ var pipelineLayoutCreateInfo = new PipelineLayoutCreateInfo()
+ {
+ SType = StructureType.PipelineLayoutCreateInfo,
+ PSetLayouts = pLayouts,
+ SetLayoutCount = PipelineBase.DescriptorSetLayouts
+ };
+
+ gd.Api.CreatePipelineLayout(device, &pipelineLayoutCreateInfo, null, out layout).ThrowOnError();
+ }
+
+ return layouts;
+ }
+ }
+}