diff --git a/src/Ryujinx.Graphics.GAL/Capabilities.cs b/src/Ryujinx.Graphics.GAL/Capabilities.cs
index d758586ae4..a5c6eb5c8e 100644
--- a/src/Ryujinx.Graphics.GAL/Capabilities.cs
+++ b/src/Ryujinx.Graphics.GAL/Capabilities.cs
@@ -51,6 +51,13 @@ namespace Ryujinx.Graphics.GAL
public readonly bool SupportsIndirectParameters;
public readonly bool SupportsDepthClipControl;
+ public readonly int UniformBufferSetIndex;
+ public readonly int StorageBufferSetIndex;
+ public readonly int TextureSetIndex;
+ public readonly int ImageSetIndex;
+ public readonly int ExtraSetBaseIndex;
+ public readonly int MaximumExtraSets;
+
public readonly uint MaximumUniformBuffersPerStage;
public readonly uint MaximumStorageBuffersPerStage;
public readonly uint MaximumTexturesPerStage;
@@ -109,6 +116,12 @@ namespace Ryujinx.Graphics.GAL
bool supportsViewportSwizzle,
bool supportsIndirectParameters,
bool supportsDepthClipControl,
+ int uniformBufferSetIndex,
+ int storageBufferSetIndex,
+ int textureSetIndex,
+ int imageSetIndex,
+ int extraSetBaseIndex,
+ int maximumExtraSets,
uint maximumUniformBuffersPerStage,
uint maximumStorageBuffersPerStage,
uint maximumTexturesPerStage,
@@ -164,6 +177,12 @@ namespace Ryujinx.Graphics.GAL
SupportsViewportSwizzle = supportsViewportSwizzle;
SupportsIndirectParameters = supportsIndirectParameters;
SupportsDepthClipControl = supportsDepthClipControl;
+ UniformBufferSetIndex = uniformBufferSetIndex;
+ StorageBufferSetIndex = storageBufferSetIndex;
+ TextureSetIndex = textureSetIndex;
+ ImageSetIndex = imageSetIndex;
+ ExtraSetBaseIndex = extraSetBaseIndex;
+ MaximumExtraSets = maximumExtraSets;
MaximumUniformBuffersPerStage = maximumUniformBuffersPerStage;
MaximumStorageBuffersPerStage = maximumStorageBuffersPerStage;
MaximumTexturesPerStage = maximumTexturesPerStage;
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs
index 0d562b0da2..d89eebabfd 100644
--- a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs
+++ b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs
@@ -51,7 +51,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
_reservedImages = rrc.ReservedImages;
}
- public int CreateConstantBufferBinding(int index)
+ public SetBindingPair CreateConstantBufferBinding(int index)
{
int binding;
@@ -64,10 +64,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
binding = _resourceCounts.UniformBuffersCount++;
}
- return binding + _reservedConstantBuffers;
+ return new SetBindingPair(_context.Capabilities.UniformBufferSetIndex, binding + _reservedConstantBuffers);
}
- public int CreateImageBinding(int count, bool isBuffer)
+ public SetBindingPair CreateImageBinding(int count, bool isBuffer)
{
int binding;
@@ -96,10 +96,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
_resourceCounts.ImagesCount += count;
}
- return binding + _reservedImages;
+ return new SetBindingPair(_context.Capabilities.ImageSetIndex, binding + _reservedImages);
}
- public int CreateStorageBufferBinding(int index)
+ public SetBindingPair CreateStorageBufferBinding(int index)
{
int binding;
@@ -112,10 +112,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
binding = _resourceCounts.StorageBuffersCount++;
}
- return binding + _reservedStorageBuffers;
+ return new SetBindingPair(_context.Capabilities.StorageBufferSetIndex, binding + _reservedStorageBuffers);
}
- public int CreateTextureBinding(int count, bool isBuffer)
+ public SetBindingPair CreateTextureBinding(int count, bool isBuffer)
{
int binding;
@@ -144,7 +144,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
_resourceCounts.TexturesCount += count;
}
- return binding + _reservedTextures;
+ return new SetBindingPair(_context.Capabilities.TextureSetIndex, binding + _reservedTextures);
}
private int GetBindingFromIndex(int index, uint maxPerStage, string resourceName)
@@ -183,6 +183,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
return maxPerStage * Constants.ShaderStages;
}
+ public int CreateExtraSet()
+ {
+ if (_resourceCounts.SetsCount >= _context.Capabilities.MaximumExtraSets)
+ {
+ return -1;
+ }
+
+ return _context.Capabilities.ExtraSetBaseIndex + _resourceCounts.SetsCount++;
+ }
+
public int QueryHostGatherBiasPrecision() => _context.Capabilities.GatherBiasPrecision;
public bool QueryHostReducedPrecision() => _context.Capabilities.ReduceShaderPrecision;
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/ResourceCounts.cs b/src/Ryujinx.Graphics.Gpu/Shader/ResourceCounts.cs
index 126e3249c0..59ab378cf8 100644
--- a/src/Ryujinx.Graphics.Gpu/Shader/ResourceCounts.cs
+++ b/src/Ryujinx.Graphics.Gpu/Shader/ResourceCounts.cs
@@ -24,5 +24,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// Total of images used by the shaders.
///
public int ImagesCount;
+
+ ///
+ /// Total of extra sets used by the shaders.
+ ///
+ public int SetsCount;
}
}
diff --git a/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs b/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs
index 7bcff947e4..ba9cd45c67 100644
--- a/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs
+++ b/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs
@@ -187,6 +187,12 @@ namespace Ryujinx.Graphics.OpenGL
supportsViewportSwizzle: HwCapabilities.SupportsViewportSwizzle,
supportsIndirectParameters: HwCapabilities.SupportsIndirectParameters,
supportsDepthClipControl: true,
+ uniformBufferSetIndex: 0,
+ storageBufferSetIndex: 1,
+ textureSetIndex: 2,
+ imageSetIndex: 3,
+ extraSetBaseIndex: 0,
+ maximumExtraSets: 0,
maximumUniformBuffersPerStage: 13, // TODO: Avoid hardcoding those limits here and get from driver?
maximumStorageBuffersPerStage: 16,
maximumTexturesPerStage: 32,
diff --git a/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs b/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs
index 3dc4ad907b..ef692e5797 100644
--- a/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs
+++ b/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs
@@ -1,4 +1,4 @@
-using Ryujinx.Graphics.Shader.CodeGen;
+using Ryujinx.Graphics.Shader.CodeGen;
using System;
namespace Ryujinx.Graphics.Shader
@@ -27,34 +27,43 @@ namespace Ryujinx.Graphics.Shader
ReadOnlySpan GetCode(ulong address, int minimumSize);
///
- /// Queries the binding number of a constant buffer.
+ /// Gets the binding number of a constant buffer.
///
/// Constant buffer index
/// Binding number
- int CreateConstantBufferBinding(int index);
+ SetBindingPair CreateConstantBufferBinding(int index);
///
- /// Queries the binding number of an image.
+ /// Gets the binding number of an image.
///
/// For array of images, the number of elements of the array, otherwise it should be 1
/// Indicates if the image is a buffer image
/// Binding number
- int CreateImageBinding(int count, bool isBuffer);
+ SetBindingPair CreateImageBinding(int count, bool isBuffer);
///
- /// Queries the binding number of a storage buffer.
+ /// Gets the binding number of a storage buffer.
///
/// Storage buffer index
/// Binding number
- int CreateStorageBufferBinding(int index);
+ SetBindingPair CreateStorageBufferBinding(int index);
///
- /// Queries the binding number of a texture.
+ /// Gets the binding number of a texture.
///
/// For array of textures, the number of elements of the array, otherwise it should be 1
/// Indicates if the texture is a buffer texture
/// Binding number
- int CreateTextureBinding(int count, bool isBuffer);
+ SetBindingPair CreateTextureBinding(int count, bool isBuffer);
+
+ ///
+ /// Gets the set index for an additional set, or -1 if there's no extra set available.
+ ///
+ /// Extra set index, or -1 if not available
+ int CreateExtraSet()
+ {
+ return -1;
+ }
///
/// Queries Local Size X for compute shaders.
diff --git a/src/Ryujinx.Graphics.Shader/SetBindingPair.cs b/src/Ryujinx.Graphics.Shader/SetBindingPair.cs
new file mode 100644
index 0000000000..20e2d7d1c3
--- /dev/null
+++ b/src/Ryujinx.Graphics.Shader/SetBindingPair.cs
@@ -0,0 +1,41 @@
+using System;
+
+namespace Ryujinx.Graphics.Shader
+{
+ public readonly struct SetBindingPair : IEquatable
+ {
+ public readonly int SetIndex;
+ public readonly int Binding;
+
+ public SetBindingPair(int setIndex, int binding)
+ {
+ SetIndex = setIndex;
+ Binding = binding;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return obj is SetBindingPair other && Equals(other);
+ }
+
+ public bool Equals(SetBindingPair other)
+ {
+ return SetIndex == other.SetIndex && Binding == other.Binding;
+ }
+
+ public override int GetHashCode()
+ {
+ return (((ulong)(uint)SetIndex << 32) | (uint)Binding).GetHashCode();
+ }
+
+ public static bool operator ==(SetBindingPair left, SetBindingPair right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(SetBindingPair left, SetBindingPair right)
+ {
+ return !(left == right);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs b/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs
index 890501c919..c0217c43da 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs
@@ -33,6 +33,7 @@ namespace Ryujinx.Graphics.Shader.Translation
private struct TextureMeta
{
+ public int Set;
public int Binding;
public bool AccurateType;
public SamplerType Type;
@@ -149,10 +150,11 @@ namespace Ryujinx.Graphics.Shader.Translation
int binding = _cbSlotToBindingMap[slot];
if (binding < 0)
{
- binding = _gpuAccessor.CreateConstantBufferBinding(slot);
+ SetBindingPair setAndBinding = _gpuAccessor.CreateConstantBufferBinding(slot);
+ binding = setAndBinding.Binding;
_cbSlotToBindingMap[slot] = binding;
string slotNumber = slot.ToString(CultureInfo.InvariantCulture);
- AddNewConstantBuffer(binding, $"{_stagePrefix}_c{slotNumber}");
+ AddNewConstantBuffer(setAndBinding.SetIndex, binding, $"{_stagePrefix}_c{slotNumber}");
}
return binding;
@@ -170,10 +172,11 @@ namespace Ryujinx.Graphics.Shader.Translation
if (binding < 0)
{
- binding = _gpuAccessor.CreateStorageBufferBinding(slot);
+ SetBindingPair setAndBinding = _gpuAccessor.CreateStorageBufferBinding(slot);
+ binding = setAndBinding.Binding;
_sbSlotToBindingMap[slot] = binding;
string slotNumber = slot.ToString(CultureInfo.InvariantCulture);
- AddNewStorageBuffer(binding, $"{_stagePrefix}_s{slotNumber}");
+ AddNewStorageBuffer(setAndBinding.SetIndex, binding, $"{_stagePrefix}_s{slotNumber}");
}
if (write)
@@ -311,21 +314,26 @@ namespace Ryujinx.Graphics.Shader.Translation
UsageFlags = usageFlags,
};
+ int setIndex;
int binding;
if (dict.TryGetValue(info, out var existingMeta))
{
dict[info] = MergeTextureMeta(meta, existingMeta);
+ setIndex = existingMeta.Set;
binding = existingMeta.Binding;
}
else
{
bool isBuffer = (type & SamplerType.Mask) == SamplerType.TextureBuffer;
- binding = isImage
+ SetBindingPair setAndBinding = isImage
? _gpuAccessor.CreateImageBinding(arrayLength, isBuffer)
: _gpuAccessor.CreateTextureBinding(arrayLength, isBuffer);
+ setIndex = setAndBinding.SetIndex;
+ binding = setAndBinding.Binding;
+ meta.Set = setIndex;
meta.Binding = binding;
dict.Add(info, meta);
@@ -355,7 +363,7 @@ namespace Ryujinx.Graphics.Shader.Translation
}
var definition = new TextureDefinition(
- isImage ? 3 : 2,
+ setIndex,
binding,
arrayLength,
separate,
@@ -378,6 +386,7 @@ namespace Ryujinx.Graphics.Shader.Translation
private static TextureMeta MergeTextureMeta(TextureMeta meta, TextureMeta existingMeta)
{
+ meta.Set = existingMeta.Set;
meta.Binding = existingMeta.Binding;
meta.UsageFlags |= existingMeta.UsageFlags;
@@ -587,24 +596,24 @@ namespace Ryujinx.Graphics.Shader.Translation
return false;
}
- private void AddNewConstantBuffer(int binding, string name)
+ private void AddNewConstantBuffer(int setIndex, int binding, string name)
{
StructureType type = new(new[]
{
new StructureField(AggregateType.Array | AggregateType.Vector4 | AggregateType.FP32, "data", Constants.ConstantBufferSize / 16),
});
- Properties.AddOrUpdateConstantBuffer(new(BufferLayout.Std140, 0, binding, name, type));
+ Properties.AddOrUpdateConstantBuffer(new(BufferLayout.Std140, setIndex, binding, name, type));
}
- private void AddNewStorageBuffer(int binding, string name)
+ private void AddNewStorageBuffer(int setIndex, int binding, string name)
{
StructureType type = new(new[]
{
new StructureField(AggregateType.Array | AggregateType.U32, "data", 0),
});
- Properties.AddOrUpdateStorageBuffer(new(BufferLayout.Std430, 1, binding, name, type));
+ Properties.AddOrUpdateStorageBuffer(new(BufferLayout.Std430, setIndex, binding, name, type));
}
public static string GetShaderStagePrefix(ShaderStage stage)
diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs
index 175d5e3ea3..86a347e019 100644
--- a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs
+++ b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs
@@ -728,6 +728,12 @@ namespace Ryujinx.Graphics.Vulkan
supportsViewportSwizzle: false,
supportsIndirectParameters: true,
supportsDepthClipControl: Capabilities.SupportsDepthClipControl,
+ uniformBufferSetIndex: PipelineBase.UniformSetIndex,
+ storageBufferSetIndex: PipelineBase.StorageSetIndex,
+ textureSetIndex: PipelineBase.TextureSetIndex,
+ imageSetIndex: PipelineBase.ImageSetIndex,
+ extraSetBaseIndex: PipelineBase.DescriptorSetLayouts,
+ maximumExtraSets: Math.Max(0, (int)limits.MaxBoundDescriptorSets - PipelineBase.DescriptorSetLayouts),
maximumUniformBuffersPerStage: Constants.MaxUniformBuffersPerStage,
maximumStorageBuffersPerStage: Constants.MaxStorageBuffersPerStage,
maximumTexturesPerStage: Constants.MaxTexturesPerStage,
diff --git a/src/Ryujinx.ShaderTools/Program.cs b/src/Ryujinx.ShaderTools/Program.cs
index d2c6bd59e4..a11264b637 100644
--- a/src/Ryujinx.ShaderTools/Program.cs
+++ b/src/Ryujinx.ShaderTools/Program.cs
@@ -1,4 +1,4 @@
-using CommandLine;
+using CommandLine;
using Ryujinx.Graphics.Shader;
using Ryujinx.Graphics.Shader.Translation;
using System;
@@ -25,32 +25,32 @@ namespace Ryujinx.ShaderTools
_imagesCount = 0;
}
- public int CreateConstantBufferBinding(int index)
+ public SetBindingPair CreateConstantBufferBinding(int index)
{
- return index + 1;
+ return new SetBindingPair(0, index + 1);
}
- public int CreateImageBinding(int count, bool isBuffer)
+ public SetBindingPair CreateImageBinding(int count, bool isBuffer)
{
int binding = _imagesCount;
_imagesCount += count;
- return binding;
+ return new SetBindingPair(3, binding);
}
- public int CreateStorageBufferBinding(int index)
+ public SetBindingPair CreateStorageBufferBinding(int index)
{
- return index;
+ return new SetBindingPair(1, index);
}
- public int CreateTextureBinding(int count, bool isBuffer)
+ public SetBindingPair CreateTextureBinding(int count, bool isBuffer)
{
int binding = _texturesCount;
_texturesCount += count;
- return binding;
+ return new SetBindingPair(2, binding);
}
public ReadOnlySpan GetCode(ulong address, int minimumSize)