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