Start using extra sets for array textures

This commit is contained in:
Gabriel A 2024-05-24 23:22:36 -03:00
commit 7f5ef5bc47
18 changed files with 475 additions and 84 deletions

View file

@ -60,6 +60,7 @@ namespace Ryujinx.Graphics.GAL
void SetImage(ShaderStage stage, int binding, ITexture texture, Format imageFormat); void SetImage(ShaderStage stage, int binding, ITexture texture, Format imageFormat);
void SetImageArray(ShaderStage stage, int binding, IImageArray array); void SetImageArray(ShaderStage stage, int binding, IImageArray array);
void SetImageArray(ShaderStage stage, int setIndex, int binding, IImageArray array);
void SetLineParameters(float width, bool smooth); void SetLineParameters(float width, bool smooth);
@ -91,6 +92,7 @@ namespace Ryujinx.Graphics.GAL
void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler); void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler);
void SetTextureArray(ShaderStage stage, int binding, ITextureArray array); void SetTextureArray(ShaderStage stage, int binding, ITextureArray array);
void SetTextureArray(ShaderStage stage, int setIndex, int binding, ITextureArray array);
void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers); void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers);
void SetUniformBuffers(ReadOnlySpan<BufferAssignment> buffers); void SetUniformBuffers(ReadOnlySpan<BufferAssignment> buffers);

View file

@ -8,19 +8,39 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{ {
public readonly CommandType CommandType => CommandType.SetImageArray; public readonly CommandType CommandType => CommandType.SetImageArray;
private ShaderStage _stage; private ShaderStage _stage;
private bool _hasSetIndex;
private int _setIndex;
private int _binding; private int _binding;
private TableRef<IImageArray> _array; private TableRef<IImageArray> _array;
public void Set(ShaderStage stage, int binding, TableRef<IImageArray> array) public void Set(ShaderStage stage, int binding, TableRef<IImageArray> array)
{ {
_stage = stage; _stage = stage;
_hasSetIndex = false;
_setIndex = 0;
_binding = binding;
_array = array;
}
public void Set(ShaderStage stage, int setIndex, int binding, TableRef<IImageArray> array)
{
_stage = stage;
_hasSetIndex = true;
_setIndex = setIndex;
_binding = binding; _binding = binding;
_array = array; _array = array;
} }
public static void Run(ref SetImageArrayCommand command, ThreadedRenderer threaded, IRenderer renderer) public static void Run(ref SetImageArrayCommand command, ThreadedRenderer threaded, IRenderer renderer)
{ {
renderer.Pipeline.SetImageArray(command._stage, command._binding, command._array.GetAs<ThreadedImageArray>(threaded)?.Base); if (command._hasSetIndex)
{
renderer.Pipeline.SetImageArray(command._stage, command._setIndex, command._binding, command._array.GetAs<ThreadedImageArray>(threaded)?.Base);
}
else
{
renderer.Pipeline.SetImageArray(command._stage, command._binding, command._array.GetAs<ThreadedImageArray>(threaded)?.Base);
}
} }
} }
} }

View file

@ -8,19 +8,39 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{ {
public readonly CommandType CommandType => CommandType.SetTextureArray; public readonly CommandType CommandType => CommandType.SetTextureArray;
private ShaderStage _stage; private ShaderStage _stage;
private bool _hasSetIndex;
private int _setIndex;
private int _binding; private int _binding;
private TableRef<ITextureArray> _array; private TableRef<ITextureArray> _array;
public void Set(ShaderStage stage, int binding, TableRef<ITextureArray> array) public void Set(ShaderStage stage, int binding, TableRef<ITextureArray> array)
{ {
_stage = stage; _stage = stage;
_hasSetIndex = false;
_setIndex = 0;
_binding = binding;
_array = array;
}
public void Set(ShaderStage stage, int setIndex, int binding, TableRef<ITextureArray> array)
{
_stage = stage;
_hasSetIndex = true;
_setIndex = setIndex;
_binding = binding; _binding = binding;
_array = array; _array = array;
} }
public static void Run(ref SetTextureArrayCommand command, ThreadedRenderer threaded, IRenderer renderer) public static void Run(ref SetTextureArrayCommand command, ThreadedRenderer threaded, IRenderer renderer)
{ {
renderer.Pipeline.SetTextureArray(command._stage, command._binding, command._array.GetAs<ThreadedTextureArray>(threaded)?.Base); if (command._hasSetIndex)
{
renderer.Pipeline.SetTextureArray(command._stage, command._setIndex, command._binding, command._array.GetAs<ThreadedTextureArray>(threaded)?.Base);
}
else
{
renderer.Pipeline.SetTextureArray(command._stage, command._binding, command._array.GetAs<ThreadedTextureArray>(threaded)?.Base);
}
} }
} }
} }

View file

@ -189,6 +189,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetImageArray(ShaderStage stage, int setIndex, int binding, IImageArray array)
{
_renderer.New<SetImageArrayCommand>().Set(stage, setIndex, binding, Ref(array));
_renderer.QueueCommand();
}
public void SetIndexBuffer(BufferRange buffer, IndexType type) public void SetIndexBuffer(BufferRange buffer, IndexType type)
{ {
_renderer.New<SetIndexBufferCommand>().Set(buffer, type); _renderer.New<SetIndexBufferCommand>().Set(buffer, type);
@ -297,6 +303,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetTextureArray(ShaderStage stage, int setIndex, int binding, ITextureArray array)
{
_renderer.New<SetTextureArrayCommand>().Set(stage, setIndex, binding, Ref(array));
_renderer.QueueCommand();
}
public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers) public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers)
{ {
_renderer.New<SetTransformFeedbackBuffersCommand>().Set(_renderer.CopySpan(buffers)); _renderer.New<SetTransformFeedbackBuffersCommand>().Set(_renderer.CopySpan(buffers));

View file

@ -19,6 +19,11 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary> /// </summary>
public Format Format { get; } public Format Format { get; }
/// <summary>
/// Shader texture host set index.
/// </summary>
public int Set { get; }
/// <summary> /// <summary>
/// Shader texture host binding point. /// Shader texture host binding point.
/// </summary> /// </summary>
@ -54,15 +59,17 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary> /// </summary>
/// <param name="target">The shader sampler target type</param> /// <param name="target">The shader sampler target type</param>
/// <param name="format">Format of the image as declared on the shader</param> /// <param name="format">Format of the image as declared on the shader</param>
/// <param name="set">Shader texture host set index</param>
/// <param name="binding">The shader texture binding point</param> /// <param name="binding">The shader texture binding point</param>
/// <param name="arrayLength">For array of textures, this indicates the length of the array. A value of one indicates it is not an array</param> /// <param name="arrayLength">For array of textures, this indicates the length of the array. A value of one indicates it is not an array</param>
/// <param name="cbufSlot">Constant buffer slot where the texture handle is located</param> /// <param name="cbufSlot">Constant buffer slot where the texture handle is located</param>
/// <param name="handle">The shader texture handle (read index into the texture constant buffer)</param> /// <param name="handle">The shader texture handle (read index into the texture constant buffer)</param>
/// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param> /// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param>
public TextureBindingInfo(Target target, Format format, int binding, int arrayLength, int cbufSlot, int handle, TextureUsageFlags flags) public TextureBindingInfo(Target target, Format format, int set, int binding, int arrayLength, int cbufSlot, int handle, TextureUsageFlags flags)
{ {
Target = target; Target = target;
Format = format; Format = format;
Set = set;
Binding = binding; Binding = binding;
ArrayLength = arrayLength; ArrayLength = arrayLength;
CbufSlot = cbufSlot; CbufSlot = cbufSlot;
@ -74,6 +81,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Constructs the texture binding information structure. /// Constructs the texture binding information structure.
/// </summary> /// </summary>
/// <param name="target">The shader sampler target type</param> /// <param name="target">The shader sampler target type</param>
/// <param name="set">Shader texture host set index</param>
/// <param name="binding">The shader texture binding point</param> /// <param name="binding">The shader texture binding point</param>
/// <param name="arrayLength">For array of textures, this indicates the length of the array. A value of one indicates it is not an array</param> /// <param name="arrayLength">For array of textures, this indicates the length of the array. A value of one indicates it is not an array</param>
/// <param name="cbufSlot">Constant buffer slot where the texture handle is located</param> /// <param name="cbufSlot">Constant buffer slot where the texture handle is located</param>
@ -82,12 +90,13 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="isSamplerOnly">Indicates that the binding is for a sampler</param> /// <param name="isSamplerOnly">Indicates that the binding is for a sampler</param>
public TextureBindingInfo( public TextureBindingInfo(
Target target, Target target,
int set,
int binding, int binding,
int arrayLength, int arrayLength,
int cbufSlot, int cbufSlot,
int handle, int handle,
TextureUsageFlags flags, TextureUsageFlags flags,
bool isSamplerOnly) : this(target, 0, binding, arrayLength, cbufSlot, handle, flags) bool isSamplerOnly) : this(target, 0, set, binding, arrayLength, cbufSlot, handle, flags)
{ {
IsSamplerOnly = isSamplerOnly; IsSamplerOnly = isSamplerOnly;
} }

View file

@ -566,7 +566,7 @@ namespace Ryujinx.Graphics.Gpu.Image
int stageIndex, int stageIndex,
int textureBufferIndex, int textureBufferIndex,
SamplerIndex samplerIndex, SamplerIndex samplerIndex,
TextureBindingInfo bindingInfo) in TextureBindingInfo bindingInfo)
{ {
Update(texturePool, samplerPool, stage, stageIndex, textureBufferIndex, isImage: false, samplerIndex, bindingInfo); Update(texturePool, samplerPool, stage, stageIndex, textureBufferIndex, isImage: false, samplerIndex, bindingInfo);
} }
@ -579,7 +579,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="stageIndex">Shader stage index where the array is used</param> /// <param name="stageIndex">Shader stage index where the array is used</param>
/// <param name="textureBufferIndex">Texture constant buffer index</param> /// <param name="textureBufferIndex">Texture constant buffer index</param>
/// <param name="bindingInfo">Array binding information</param> /// <param name="bindingInfo">Array binding information</param>
public void UpdateImageArray(TexturePool texturePool, ShaderStage stage, int stageIndex, int textureBufferIndex, TextureBindingInfo bindingInfo) public void UpdateImageArray(TexturePool texturePool, ShaderStage stage, int stageIndex, int textureBufferIndex, in TextureBindingInfo bindingInfo)
{ {
Update(texturePool, null, stage, stageIndex, textureBufferIndex, isImage: true, SamplerIndex.ViaHeaderIndex, bindingInfo); Update(texturePool, null, stage, stageIndex, textureBufferIndex, isImage: true, SamplerIndex.ViaHeaderIndex, bindingInfo);
} }
@ -603,7 +603,7 @@ namespace Ryujinx.Graphics.Gpu.Image
int textureBufferIndex, int textureBufferIndex,
bool isImage, bool isImage,
SamplerIndex samplerIndex, SamplerIndex samplerIndex,
TextureBindingInfo bindingInfo) in TextureBindingInfo bindingInfo)
{ {
if (IsDirectHandleType(bindingInfo.Handle)) if (IsDirectHandleType(bindingInfo.Handle))
{ {
@ -623,7 +623,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="stage">Shader stage where the array is used</param> /// <param name="stage">Shader stage where the array is used</param>
/// <param name="isImage">Whether the array is a image or texture array</param> /// <param name="isImage">Whether the array is a image or texture array</param>
/// <param name="bindingInfo">Array binding information</param> /// <param name="bindingInfo">Array binding information</param>
private void UpdateFromPool(TexturePool texturePool, SamplerPool samplerPool, ShaderStage stage, bool isImage, TextureBindingInfo bindingInfo) private void UpdateFromPool(TexturePool texturePool, SamplerPool samplerPool, ShaderStage stage, bool isImage, in TextureBindingInfo bindingInfo)
{ {
CacheEntry entry = GetOrAddEntry(texturePool, samplerPool, bindingInfo, isImage, out bool isNewEntry); CacheEntry entry = GetOrAddEntry(texturePool, samplerPool, bindingInfo, isImage, out bool isNewEntry);
@ -638,11 +638,11 @@ namespace Ryujinx.Graphics.Gpu.Image
if (isImage) if (isImage)
{ {
_context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray); SetImageArray(stage, bindingInfo, entry.ImageArray);
} }
else else
{ {
_context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray); SetTextureArray(stage, bindingInfo, entry.TextureArray);
} }
return; return;
@ -737,14 +737,14 @@ namespace Ryujinx.Graphics.Gpu.Image
entry.ImageArray.SetFormats(0, formats); entry.ImageArray.SetFormats(0, formats);
entry.ImageArray.SetImages(0, textures); entry.ImageArray.SetImages(0, textures);
_context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray); SetImageArray(stage, bindingInfo, entry.ImageArray);
} }
else else
{ {
entry.TextureArray.SetSamplers(0, samplers); entry.TextureArray.SetSamplers(0, samplers);
entry.TextureArray.SetTextures(0, textures); entry.TextureArray.SetTextures(0, textures);
_context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray); SetTextureArray(stage, bindingInfo, entry.TextureArray);
} }
} }
@ -767,7 +767,7 @@ namespace Ryujinx.Graphics.Gpu.Image
int textureBufferIndex, int textureBufferIndex,
bool isImage, bool isImage,
SamplerIndex samplerIndex, SamplerIndex samplerIndex,
TextureBindingInfo bindingInfo) in TextureBindingInfo bindingInfo)
{ {
(textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(bindingInfo.CbufSlot, textureBufferIndex); (textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(bindingInfo.CbufSlot, textureBufferIndex);
@ -800,11 +800,11 @@ namespace Ryujinx.Graphics.Gpu.Image
if (isImage) if (isImage)
{ {
_context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray); SetImageArray(stage, bindingInfo, entry.ImageArray);
} }
else else
{ {
_context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray); SetTextureArray(stage, bindingInfo, entry.TextureArray);
} }
return; return;
@ -829,11 +829,11 @@ namespace Ryujinx.Graphics.Gpu.Image
if (isImage) if (isImage)
{ {
_context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray); SetImageArray(stage, bindingInfo, entry.ImageArray);
} }
else else
{ {
_context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray); SetTextureArray(stage, bindingInfo, entry.TextureArray);
} }
return; return;
@ -950,14 +950,38 @@ namespace Ryujinx.Graphics.Gpu.Image
entry.ImageArray.SetFormats(0, formats); entry.ImageArray.SetFormats(0, formats);
entry.ImageArray.SetImages(0, textures); entry.ImageArray.SetImages(0, textures);
_context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray); SetImageArray(stage, bindingInfo, entry.ImageArray);
} }
else else
{ {
entry.TextureArray.SetSamplers(0, samplers); entry.TextureArray.SetSamplers(0, samplers);
entry.TextureArray.SetTextures(0, textures); entry.TextureArray.SetTextures(0, textures);
_context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray); SetTextureArray(stage, bindingInfo, entry.TextureArray);
}
}
private void SetTextureArray(ShaderStage stage, in TextureBindingInfo bindingInfo, ITextureArray array)
{
if (bindingInfo.Set >= _context.Capabilities.ExtraSetBaseIndex)
{
_context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Set, bindingInfo.Binding, array);
}
else
{
_context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, array);
}
}
private void SetImageArray(ShaderStage stage, in TextureBindingInfo bindingInfo, IImageArray array)
{
if (bindingInfo.Set >= _context.Capabilities.ExtraSetBaseIndex)
{
_context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Set, bindingInfo.Binding, array);
}
else
{
_context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, array);
} }
} }
@ -973,7 +997,7 @@ namespace Ryujinx.Graphics.Gpu.Image
private CacheEntry GetOrAddEntry( private CacheEntry GetOrAddEntry(
TexturePool texturePool, TexturePool texturePool,
SamplerPool samplerPool, SamplerPool samplerPool,
TextureBindingInfo bindingInfo, in TextureBindingInfo bindingInfo,
bool isImage, bool isImage,
out bool isNew) out bool isNew)
{ {
@ -1015,7 +1039,7 @@ namespace Ryujinx.Graphics.Gpu.Image
private CacheEntryFromBuffer GetOrAddEntry( private CacheEntryFromBuffer GetOrAddEntry(
TexturePool texturePool, TexturePool texturePool,
SamplerPool samplerPool, SamplerPool samplerPool,
TextureBindingInfo bindingInfo, in TextureBindingInfo bindingInfo,
bool isImage, bool isImage,
ref BufferBounds textureBufferBounds, ref BufferBounds textureBufferBounds,
out bool isNew) out bool isNew)

View file

@ -62,6 +62,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
var result = new TextureBindingInfo( var result = new TextureBindingInfo(
target, target,
descriptor.Set,
descriptor.Binding, descriptor.Binding,
descriptor.ArrayLength, descriptor.ArrayLength,
descriptor.CbufSlot, descriptor.CbufSlot,
@ -90,6 +91,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
var result = new TextureBindingInfo( var result = new TextureBindingInfo(
target, target,
format, format,
descriptor.Set,
descriptor.Binding, descriptor.Binding,
descriptor.ArrayLength, descriptor.ArrayLength,
descriptor.CbufSlot, descriptor.CbufSlot,

View file

@ -1,5 +1,6 @@
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Shader; using Ryujinx.Graphics.Shader;
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace Ryujinx.Graphics.Gpu.Shader namespace Ryujinx.Graphics.Gpu.Shader
@ -36,8 +37,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
private readonly int _reservedTextures; private readonly int _reservedTextures;
private readonly int _reservedImages; private readonly int _reservedImages;
private readonly List<ResourceDescriptor>[] _resourceDescriptors; private List<ResourceDescriptor>[] _resourceDescriptors;
private readonly List<ResourceUsage>[] _resourceUsages; private List<ResourceUsage>[] _resourceUsages;
/// <summary> /// <summary>
/// Creates a new shader info builder. /// Creates a new shader info builder.
@ -132,13 +133,13 @@ namespace Ryujinx.Graphics.Gpu.Shader
AddDualDescriptor(stages, ResourceType.TextureAndSampler, ResourceType.BufferTexture, TextureSetIndex, textureBinding, texturesPerStage); AddDualDescriptor(stages, ResourceType.TextureAndSampler, ResourceType.BufferTexture, TextureSetIndex, textureBinding, texturesPerStage);
AddDualDescriptor(stages, ResourceType.Image, ResourceType.BufferImage, ImageSetIndex, imageBinding, imagesPerStage); AddDualDescriptor(stages, ResourceType.Image, ResourceType.BufferImage, ImageSetIndex, imageBinding, imagesPerStage);
AddArrayDescriptors(info.Textures, stages, TextureSetIndex, isImage: false); AddArrayDescriptors(info.Textures, stages, isImage: false);
AddArrayDescriptors(info.Images, stages, TextureSetIndex, isImage: true); AddArrayDescriptors(info.Images, stages, isImage: true);
AddUsage(info.CBuffers, stages, UniformSetIndex, isStorage: false); AddUsage(info.CBuffers, stages, isStorage: false);
AddUsage(info.SBuffers, stages, StorageSetIndex, isStorage: true); AddUsage(info.SBuffers, stages, isStorage: true);
AddUsage(info.Textures, stages, TextureSetIndex, isImage: false); AddUsage(info.Textures, stages, isImage: false);
AddUsage(info.Images, stages, ImageSetIndex, isImage: true); AddUsage(info.Images, stages, isImage: true);
} }
/// <summary> /// <summary>
@ -177,9 +178,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// </summary> /// </summary>
/// <param name="textures">Textures to be added</param> /// <param name="textures">Textures to be added</param>
/// <param name="stages">Stages where the textures are used</param> /// <param name="stages">Stages where the textures are used</param>
/// <param name="setIndex">Descriptor set index where the textures will be bound</param>
/// <param name="isImage">True for images, false for textures</param> /// <param name="isImage">True for images, false for textures</param>
private void AddArrayDescriptors(IEnumerable<TextureDescriptor> textures, ResourceStages stages, int setIndex, bool isImage) private void AddArrayDescriptors(IEnumerable<TextureDescriptor> textures, ResourceStages stages, bool isImage)
{ {
foreach (TextureDescriptor texture in textures) foreach (TextureDescriptor texture in textures)
{ {
@ -187,7 +187,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
{ {
ResourceType type = GetTextureResourceType(texture, isImage); ResourceType type = GetTextureResourceType(texture, isImage);
_resourceDescriptors[setIndex].Add(new ResourceDescriptor(texture.Binding, texture.ArrayLength, type, stages)); GetDescriptors(texture.Set).Add(new ResourceDescriptor(texture.Binding, texture.ArrayLength, type, stages));
} }
} }
} }
@ -213,13 +213,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// </summary> /// </summary>
/// <param name="buffers">Buffers to be added</param> /// <param name="buffers">Buffers to be added</param>
/// <param name="stages">Stages where the buffers are used</param> /// <param name="stages">Stages where the buffers are used</param>
/// <param name="setIndex">Descriptor set index where the buffers will be bound</param>
/// <param name="isStorage">True for storage buffers, false for uniform buffers</param> /// <param name="isStorage">True for storage buffers, false for uniform buffers</param>
private void AddUsage(IEnumerable<BufferDescriptor> buffers, ResourceStages stages, int setIndex, bool isStorage) private void AddUsage(IEnumerable<BufferDescriptor> buffers, ResourceStages stages, bool isStorage)
{ {
foreach (BufferDescriptor buffer in buffers) foreach (BufferDescriptor buffer in buffers)
{ {
_resourceUsages[setIndex].Add(new ResourceUsage( GetUsages(buffer.Set).Add(new ResourceUsage(
buffer.Binding, buffer.Binding,
1, 1,
isStorage ? ResourceType.StorageBuffer : ResourceType.UniformBuffer, isStorage ? ResourceType.StorageBuffer : ResourceType.UniformBuffer,
@ -232,18 +231,49 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// </summary> /// </summary>
/// <param name="textures">Textures to be added</param> /// <param name="textures">Textures to be added</param>
/// <param name="stages">Stages where the textures are used</param> /// <param name="stages">Stages where the textures are used</param>
/// <param name="setIndex">Descriptor set index where the textures will be bound</param>
/// <param name="isImage">True for images, false for textures</param> /// <param name="isImage">True for images, false for textures</param>
private void AddUsage(IEnumerable<TextureDescriptor> textures, ResourceStages stages, int setIndex, bool isImage) private void AddUsage(IEnumerable<TextureDescriptor> textures, ResourceStages stages, bool isImage)
{ {
foreach (TextureDescriptor texture in textures) foreach (TextureDescriptor texture in textures)
{ {
ResourceType type = GetTextureResourceType(texture, isImage); ResourceType type = GetTextureResourceType(texture, isImage);
_resourceUsages[setIndex].Add(new ResourceUsage(texture.Binding, texture.ArrayLength, type, stages)); GetUsages(texture.Set).Add(new ResourceUsage(texture.Binding, texture.ArrayLength, type, stages));
} }
} }
private List<ResourceDescriptor> GetDescriptors(int setIndex)
{
if (_resourceDescriptors.Length <= setIndex)
{
int oldLength = _resourceDescriptors.Length;
Array.Resize(ref _resourceDescriptors, setIndex + 1);
for (int index = oldLength; index <= setIndex; index++)
{
_resourceDescriptors[index] = new();
}
}
return _resourceDescriptors[setIndex];
}
private List<ResourceUsage> GetUsages(int setIndex)
{
if (_resourceUsages.Length <= setIndex)
{
int oldLength = _resourceUsages.Length;
Array.Resize(ref _resourceUsages, setIndex + 1);
for (int index = oldLength; index <= setIndex; index++)
{
_resourceUsages[index] = new();
}
}
return _resourceUsages[setIndex];
}
private static ResourceType GetTextureResourceType(TextureDescriptor texture, bool isImage) private static ResourceType GetTextureResourceType(TextureDescriptor texture, bool isImage)
{ {
bool isBuffer = (texture.Type & SamplerType.Mask) == SamplerType.TextureBuffer; bool isBuffer = (texture.Type & SamplerType.Mask) == SamplerType.TextureBuffer;
@ -278,10 +308,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <returns>Shader information</returns> /// <returns>Shader information</returns>
public ShaderInfo Build(ProgramPipelineState? pipeline, bool fromCache = false) public ShaderInfo Build(ProgramPipelineState? pipeline, bool fromCache = false)
{ {
var descriptors = new ResourceDescriptorCollection[TotalSets]; int totalSets = _resourceDescriptors.Length;
var usages = new ResourceUsageCollection[TotalSets];
for (int index = 0; index < TotalSets; index++) var descriptors = new ResourceDescriptorCollection[totalSets];
var usages = new ResourceUsageCollection[totalSets];
for (int index = 0; index < totalSets; index++)
{ {
descriptors[index] = new ResourceDescriptorCollection(_resourceDescriptors[index].ToArray().AsReadOnly()); descriptors[index] = new ResourceDescriptorCollection(_resourceDescriptors[index].ToArray().AsReadOnly());
usages[index] = new ResourceUsageCollection(_resourceUsages[index].ToArray().AsReadOnly()); usages[index] = new ResourceUsageCollection(_resourceUsages[index].ToArray().AsReadOnly());

View file

@ -963,6 +963,11 @@ namespace Ryujinx.Graphics.OpenGL
(array as ImageArray).Bind(binding); (array as ImageArray).Bind(binding);
} }
public void SetImageArray(ShaderStage stage, int setIndex, int binding, IImageArray array)
{
throw new NotSupportedException("OpenGL does not support descriptor sets.");
}
public void SetIndexBuffer(BufferRange buffer, IndexType type) public void SetIndexBuffer(BufferRange buffer, IndexType type)
{ {
_elementsType = type.Convert(); _elementsType = type.Convert();
@ -1312,6 +1317,11 @@ namespace Ryujinx.Graphics.OpenGL
(array as TextureArray).Bind(binding); (array as TextureArray).Bind(binding);
} }
public void SetTextureArray(ShaderStage stage, int setIndex, int binding, ITextureArray array)
{
throw new NotSupportedException("OpenGL does not support descriptor sets.");
}
public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers) public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers)
{ {
if (_tfEnabled) if (_tfEnabled)

View file

@ -4,14 +4,16 @@ namespace Ryujinx.Graphics.Shader
{ {
// New fields should be added to the end of the struct to keep disk shader cache compatibility. // New fields should be added to the end of the struct to keep disk shader cache compatibility.
public readonly int Set;
public readonly int Binding; public readonly int Binding;
public readonly byte Slot; public readonly byte Slot;
public readonly byte SbCbSlot; public readonly byte SbCbSlot;
public readonly ushort SbCbOffset; public readonly ushort SbCbOffset;
public readonly BufferUsageFlags Flags; public readonly BufferUsageFlags Flags;
public BufferDescriptor(int binding, int slot) public BufferDescriptor(int set, int binding, int slot)
{ {
Set = set;
Binding = binding; Binding = binding;
Slot = (byte)slot; Slot = (byte)slot;
SbCbSlot = 0; SbCbSlot = 0;
@ -19,8 +21,9 @@ namespace Ryujinx.Graphics.Shader
Flags = BufferUsageFlags.None; Flags = BufferUsageFlags.None;
} }
public BufferDescriptor(int binding, int slot, int sbCbSlot, int sbCbOffset, BufferUsageFlags flags) public BufferDescriptor(int set, int binding, int slot, int sbCbSlot, int sbCbOffset, BufferUsageFlags flags)
{ {
Set = set;
Binding = binding; Binding = binding;
Slot = (byte)slot; Slot = (byte)slot;
SbCbSlot = (byte)sbCbSlot; SbCbSlot = (byte)sbCbSlot;

View file

@ -1,4 +1,4 @@
using Ryujinx.Graphics.Shader.IntermediateRepresentation; using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using Ryujinx.Graphics.Shader.StructuredIr; using Ryujinx.Graphics.Shader.StructuredIr;
using Ryujinx.Graphics.Shader.Translation; using Ryujinx.Graphics.Shader.Translation;
using Spv.Generator; using Spv.Generator;

View file

@ -1,4 +1,4 @@
using Ryujinx.Graphics.Shader.IntermediateRepresentation; using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using Ryujinx.Graphics.Shader.StructuredIr; using Ryujinx.Graphics.Shader.StructuredIr;
using Ryujinx.Graphics.Shader.Translation; using Ryujinx.Graphics.Shader.Translation;
using System; using System;

View file

@ -4,6 +4,7 @@ namespace Ryujinx.Graphics.Shader
{ {
// New fields should be added to the end of the struct to keep disk shader cache compatibility. // New fields should be added to the end of the struct to keep disk shader cache compatibility.
public readonly int Set;
public readonly int Binding; public readonly int Binding;
public readonly SamplerType Type; public readonly SamplerType Type;
@ -18,6 +19,7 @@ namespace Ryujinx.Graphics.Shader
public readonly TextureUsageFlags Flags; public readonly TextureUsageFlags Flags;
public TextureDescriptor( public TextureDescriptor(
int set,
int binding, int binding,
SamplerType type, SamplerType type,
TextureFormat format, TextureFormat format,
@ -27,6 +29,7 @@ namespace Ryujinx.Graphics.Shader
bool separate, bool separate,
TextureUsageFlags flags) TextureUsageFlags flags)
{ {
Set = set;
Binding = binding; Binding = binding;
Type = type; Type = type;
Format = format; Format = format;

View file

@ -20,8 +20,8 @@ namespace Ryujinx.Graphics.Shader.Translation
private readonly ShaderStage _stage; private readonly ShaderStage _stage;
private readonly string _stagePrefix; private readonly string _stagePrefix;
private readonly int[] _cbSlotToBindingMap; private readonly SetBindingPair[] _cbSlotToBindingMap;
private readonly int[] _sbSlotToBindingMap; private readonly SetBindingPair[] _sbSlotToBindingMap;
private uint _sbSlotWritten; private uint _sbSlotWritten;
private readonly Dictionary<int, int> _sbSlots; private readonly Dictionary<int, int> _sbSlots;
@ -65,10 +65,10 @@ namespace Ryujinx.Graphics.Shader.Translation
_stage = stage; _stage = stage;
_stagePrefix = GetShaderStagePrefix(stage); _stagePrefix = GetShaderStagePrefix(stage);
_cbSlotToBindingMap = new int[18]; _cbSlotToBindingMap = new SetBindingPair[18];
_sbSlotToBindingMap = new int[16]; _sbSlotToBindingMap = new SetBindingPair[16];
_cbSlotToBindingMap.AsSpan().Fill(-1); _cbSlotToBindingMap.AsSpan().Fill(new(-1, -1));
_sbSlotToBindingMap.AsSpan().Fill(-1); _sbSlotToBindingMap.AsSpan().Fill(new(-1, -1));
_sbSlots = new(); _sbSlots = new();
_sbSlotsReverse = new(); _sbSlotsReverse = new();
@ -147,17 +147,16 @@ namespace Ryujinx.Graphics.Shader.Translation
public int GetConstantBufferBinding(int slot) public int GetConstantBufferBinding(int slot)
{ {
int binding = _cbSlotToBindingMap[slot]; SetBindingPair setAndBinding = _cbSlotToBindingMap[slot];
if (binding < 0) if (setAndBinding.Binding < 0)
{ {
SetBindingPair setAndBinding = _gpuAccessor.CreateConstantBufferBinding(slot); setAndBinding = _gpuAccessor.CreateConstantBufferBinding(slot);
binding = setAndBinding.Binding; _cbSlotToBindingMap[slot] = setAndBinding;
_cbSlotToBindingMap[slot] = binding;
string slotNumber = slot.ToString(CultureInfo.InvariantCulture); string slotNumber = slot.ToString(CultureInfo.InvariantCulture);
AddNewConstantBuffer(setAndBinding.SetIndex, binding, $"{_stagePrefix}_c{slotNumber}"); AddNewConstantBuffer(setAndBinding.SetIndex, setAndBinding.Binding, $"{_stagePrefix}_c{slotNumber}");
} }
return binding; return setAndBinding.Binding;
} }
public bool TryGetStorageBufferBinding(int sbCbSlot, int sbCbOffset, bool write, out int binding) public bool TryGetStorageBufferBinding(int sbCbSlot, int sbCbOffset, bool write, out int binding)
@ -168,15 +167,14 @@ namespace Ryujinx.Graphics.Shader.Translation
return false; return false;
} }
binding = _sbSlotToBindingMap[slot]; SetBindingPair setAndBinding = _sbSlotToBindingMap[slot];
if (binding < 0) if (setAndBinding.Binding < 0)
{ {
SetBindingPair setAndBinding = _gpuAccessor.CreateStorageBufferBinding(slot); setAndBinding = _gpuAccessor.CreateStorageBufferBinding(slot);
binding = setAndBinding.Binding; _sbSlotToBindingMap[slot] = setAndBinding;
_sbSlotToBindingMap[slot] = binding;
string slotNumber = slot.ToString(CultureInfo.InvariantCulture); string slotNumber = slot.ToString(CultureInfo.InvariantCulture);
AddNewStorageBuffer(setAndBinding.SetIndex, binding, $"{_stagePrefix}_s{slotNumber}"); AddNewStorageBuffer(setAndBinding.SetIndex, setAndBinding.Binding, $"{_stagePrefix}_s{slotNumber}");
} }
if (write) if (write)
@ -184,6 +182,7 @@ namespace Ryujinx.Graphics.Shader.Translation
_sbSlotWritten |= 1u << slot; _sbSlotWritten |= 1u << slot;
} }
binding = setAndBinding.Binding;
return true; return true;
} }
@ -211,7 +210,7 @@ namespace Ryujinx.Graphics.Shader.Translation
{ {
for (slot = 0; slot < _cbSlotToBindingMap.Length; slot++) for (slot = 0; slot < _cbSlotToBindingMap.Length; slot++)
{ {
if (_cbSlotToBindingMap[slot] == binding) if (_cbSlotToBindingMap[slot].Binding == binding)
{ {
return true; return true;
} }
@ -325,14 +324,22 @@ namespace Ryujinx.Graphics.Shader.Translation
} }
else else
{ {
bool isBuffer = (type & SamplerType.Mask) == SamplerType.TextureBuffer; if (arrayLength > 1 && (setIndex = _gpuAccessor.CreateExtraSet()) >= 0)
{
binding = 0;
}
else
{
bool isBuffer = (type & SamplerType.Mask) == SamplerType.TextureBuffer;
SetBindingPair setAndBinding = isImage SetBindingPair setAndBinding = isImage
? _gpuAccessor.CreateImageBinding(arrayLength, isBuffer) ? _gpuAccessor.CreateImageBinding(arrayLength, isBuffer)
: _gpuAccessor.CreateTextureBinding(arrayLength, isBuffer); : _gpuAccessor.CreateTextureBinding(arrayLength, isBuffer);
setIndex = setAndBinding.SetIndex;
binding = setAndBinding.Binding;
}
setIndex = setAndBinding.SetIndex;
binding = setAndBinding.Binding;
meta.Set = setIndex; meta.Set = setIndex;
meta.Binding = binding; meta.Binding = binding;
@ -449,11 +456,11 @@ namespace Ryujinx.Graphics.Shader.Translation
for (int slot = 0; slot < _cbSlotToBindingMap.Length; slot++) for (int slot = 0; slot < _cbSlotToBindingMap.Length; slot++)
{ {
int binding = _cbSlotToBindingMap[slot]; SetBindingPair setAndBinding = _cbSlotToBindingMap[slot];
if (binding >= 0 && _usedConstantBufferBindings.Contains(binding)) if (setAndBinding.Binding >= 0 && _usedConstantBufferBindings.Contains(setAndBinding.Binding))
{ {
descriptors[descriptorIndex++] = new BufferDescriptor(binding, slot); descriptors[descriptorIndex++] = new BufferDescriptor(setAndBinding.SetIndex, setAndBinding.Binding, slot);
} }
} }
@ -473,13 +480,13 @@ namespace Ryujinx.Graphics.Shader.Translation
foreach ((int key, int slot) in _sbSlots) foreach ((int key, int slot) in _sbSlots)
{ {
int binding = _sbSlotToBindingMap[slot]; SetBindingPair setAndBinding = _sbSlotToBindingMap[slot];
if (binding >= 0) if (setAndBinding.Binding >= 0)
{ {
(int sbCbSlot, int sbCbOffset) = UnpackSbCbInfo(key); (int sbCbSlot, int sbCbOffset) = UnpackSbCbInfo(key);
BufferUsageFlags flags = (_sbSlotWritten & (1u << slot)) != 0 ? BufferUsageFlags.Write : BufferUsageFlags.None; BufferUsageFlags flags = (_sbSlotWritten & (1u << slot)) != 0 ? BufferUsageFlags.Write : BufferUsageFlags.None;
descriptors[descriptorIndex++] = new BufferDescriptor(binding, slot, sbCbSlot, sbCbOffset, flags); descriptors[descriptorIndex++] = new BufferDescriptor(setAndBinding.SetIndex, setAndBinding.Binding, slot, sbCbSlot, sbCbOffset, flags);
} }
} }
@ -516,6 +523,7 @@ namespace Ryujinx.Graphics.Shader.Translation
} }
descriptors.Add(new TextureDescriptor( descriptors.Add(new TextureDescriptor(
meta.Set,
meta.Binding, meta.Binding,
meta.Type, meta.Type,
info.Format, info.Format,
@ -536,6 +544,7 @@ namespace Ryujinx.Graphics.Shader.Translation
} }
descriptors.Add(new TextureDescriptor( descriptors.Add(new TextureDescriptor(
meta.Set,
meta.Binding, meta.Binding,
meta.Type, meta.Type,
info.Format, info.Format,

View file

@ -81,6 +81,20 @@ namespace Ryujinx.Graphics.Vulkan
} }
} }
private record struct ArrayExtraRef<T>
{
public ShaderStage Stage;
public T Array;
public int Binding;
public ArrayExtraRef(ShaderStage stage, T array, int binding)
{
Stage = stage;
Array = array;
Binding = binding;
}
}
private readonly VulkanRenderer _gd; private readonly VulkanRenderer _gd;
private readonly Device _device; private readonly Device _device;
private readonly PipelineBase _pipeline; private readonly PipelineBase _pipeline;
@ -97,6 +111,9 @@ namespace Ryujinx.Graphics.Vulkan
private ArrayRef<TextureArray>[] _textureArrayRefs; private ArrayRef<TextureArray>[] _textureArrayRefs;
private ArrayRef<ImageArray>[] _imageArrayRefs; private ArrayRef<ImageArray>[] _imageArrayRefs;
private ArrayExtraRef<TextureArray>[] _textureArrayExtraRefs;
private ArrayExtraRef<ImageArray>[] _imageArrayExtraRefs;
private readonly DescriptorBufferInfo[] _uniformBuffers; private readonly DescriptorBufferInfo[] _uniformBuffers;
private readonly DescriptorBufferInfo[] _storageBuffers; private readonly DescriptorBufferInfo[] _storageBuffers;
private readonly DescriptorImageInfo[] _textures; private readonly DescriptorImageInfo[] _textures;
@ -152,6 +169,9 @@ namespace Ryujinx.Graphics.Vulkan
_textureArrayRefs = Array.Empty<ArrayRef<TextureArray>>(); _textureArrayRefs = Array.Empty<ArrayRef<TextureArray>>();
_imageArrayRefs = Array.Empty<ArrayRef<ImageArray>>(); _imageArrayRefs = Array.Empty<ArrayRef<ImageArray>>();
_textureArrayExtraRefs = Array.Empty<ArrayExtraRef<TextureArray>>();
_imageArrayExtraRefs = Array.Empty<ArrayExtraRef<ImageArray>>();
_uniformBuffers = new DescriptorBufferInfo[Constants.MaxUniformBufferBindings]; _uniformBuffers = new DescriptorBufferInfo[Constants.MaxUniformBufferBindings];
_storageBuffers = new DescriptorBufferInfo[Constants.MaxStorageBufferBindings]; _storageBuffers = new DescriptorBufferInfo[Constants.MaxStorageBufferBindings];
_textures = new DescriptorImageInfo[Constants.MaxTexturesPerStage]; _textures = new DescriptorImageInfo[Constants.MaxTexturesPerStage];
@ -519,6 +539,29 @@ namespace Ryujinx.Graphics.Vulkan
} }
} }
public void SetTextureArray(CommandBufferScoped cbs, ShaderStage stage, int setIndex, int binding, ITextureArray array)
{
ref ArrayExtraRef<TextureArray> arrayRef = ref GetExtraArrayRef(ref _textureArrayExtraRefs, setIndex, binding);
if (arrayRef.Stage != stage || arrayRef.Array != array)
{
if (arrayRef.Array != null)
{
arrayRef.Array.Bound = false;
}
if (array is TextureArray textureArray)
{
textureArray.Bound = true;
textureArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags());
}
arrayRef = new ArrayExtraRef<TextureArray>(stage, array as TextureArray, binding);
SignalDirty(DirtyFlags.Texture);
}
}
public void SetImageArray(CommandBufferScoped cbs, ShaderStage stage, int binding, IImageArray array) public void SetImageArray(CommandBufferScoped cbs, ShaderStage stage, int binding, IImageArray array)
{ {
if (_imageArrayRefs.Length <= binding) if (_imageArrayRefs.Length <= binding)
@ -545,6 +588,44 @@ namespace Ryujinx.Graphics.Vulkan
} }
} }
public void SetImageArray(CommandBufferScoped cbs, ShaderStage stage, int setIndex, int binding, IImageArray array)
{
ref ArrayExtraRef<ImageArray> arrayRef = ref GetExtraArrayRef(ref _imageArrayExtraRefs, setIndex, binding);
if (arrayRef.Stage != stage || arrayRef.Array != array)
{
if (arrayRef.Array != null)
{
arrayRef.Array.Bound = false;
}
if (array is ImageArray imageArray)
{
imageArray.Bound = true;
imageArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags());
}
arrayRef = new ArrayExtraRef<ImageArray>(stage, array as ImageArray, binding);
SignalDirty(DirtyFlags.Image);
}
}
private static ref ArrayExtraRef<T> GetExtraArrayRef<T>(ref ArrayExtraRef<T>[] array, int setIndex, int binding)
{
setIndex -= PipelineBase.DescriptorSetLayouts;
ArgumentOutOfRangeException.ThrowIfNegative(setIndex);
ArgumentOutOfRangeException.ThrowIfNegative(binding);
if (array.Length <= setIndex)
{
Array.Resize(ref array, setIndex + 1);
}
return ref array[setIndex];
}
public void SetUniformBuffers(CommandBuffer commandBuffer, ReadOnlySpan<BufferAssignment> buffers) public void SetUniformBuffers(CommandBuffer commandBuffer, ReadOnlySpan<BufferAssignment> buffers)
{ {
for (int i = 0; i < buffers.Length; i++) for (int i = 0; i < buffers.Length; i++)
@ -594,31 +675,85 @@ namespace Ryujinx.Graphics.Vulkan
return; return;
} }
var program = _program;
if (_dirty.HasFlag(DirtyFlags.Uniform)) if (_dirty.HasFlag(DirtyFlags.Uniform))
{ {
if (_program.UsePushDescriptors) if (program.UsePushDescriptors)
{ {
UpdateAndBindUniformBufferPd(cbs, pbp); UpdateAndBindUniformBufferPd(cbs, pbp);
} }
else else
{ {
UpdateAndBind(cbs, PipelineBase.UniformSetIndex, pbp); UpdateAndBind(cbs, program, PipelineBase.UniformSetIndex, pbp);
} }
} }
if (_dirty.HasFlag(DirtyFlags.Storage)) if (_dirty.HasFlag(DirtyFlags.Storage))
{ {
UpdateAndBind(cbs, PipelineBase.StorageSetIndex, pbp); UpdateAndBind(cbs, program, PipelineBase.StorageSetIndex, pbp);
} }
if (_dirty.HasFlag(DirtyFlags.Texture)) if (_dirty.HasFlag(DirtyFlags.Texture))
{ {
UpdateAndBind(cbs, PipelineBase.TextureSetIndex, pbp); UpdateAndBind(cbs, program, PipelineBase.TextureSetIndex, pbp);
} }
if (_dirty.HasFlag(DirtyFlags.Image)) if (_dirty.HasFlag(DirtyFlags.Image))
{ {
UpdateAndBind(cbs, PipelineBase.ImageSetIndex, pbp); UpdateAndBind(cbs, program, PipelineBase.ImageSetIndex, pbp);
}
if (program.BindingSegments.Length > PipelineBase.DescriptorSetLayouts)
{
// Program is using extra sets, we need to bind those too.
for (int setIndex = PipelineBase.DescriptorSetLayouts; setIndex < program.BindingSegments.Length; setIndex++)
{
var bindingSegments = program.BindingSegments[setIndex];
if (bindingSegments.Length == 0)
{
continue;
}
ResourceBindingSegment segment = bindingSegments[0];
if (segment.IsArray)
{
DescriptorSet[] sets = null;
if (segment.Type == ResourceType.Texture ||
segment.Type == ResourceType.Sampler ||
segment.Type == ResourceType.TextureAndSampler ||
segment.Type == ResourceType.BufferTexture)
{
sets = _textureArrayExtraRefs[setIndex - PipelineBase.DescriptorSetLayouts].Array.GetDescriptorSets(
_device,
cbs,
_templateUpdater,
program,
setIndex,
_dummyTexture,
_dummySampler);
}
else if (segment.Type == ResourceType.Image || segment.Type == ResourceType.BufferImage)
{
sets = _imageArrayExtraRefs[setIndex - PipelineBase.DescriptorSetLayouts].Array.GetDescriptorSets(
_device,
cbs,
_templateUpdater,
program,
setIndex,
_dummyTexture);
}
if (sets != null)
{
_gd.Api.CmdBindDescriptorSets(cbs.CommandBuffer, pbp, _program.PipelineLayout, (uint)setIndex, 1, sets, 0, ReadOnlySpan<uint>.Empty);
}
}
}
} }
_dirty = DirtyFlags.None; _dirty = DirtyFlags.None;
@ -658,9 +793,8 @@ namespace Ryujinx.Graphics.Vulkan
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void UpdateAndBind(CommandBufferScoped cbs, int setIndex, PipelineBindPoint pbp) private void UpdateAndBind(CommandBufferScoped cbs, ShaderCollection program, int setIndex, PipelineBindPoint pbp)
{ {
var program = _program;
var bindingSegments = program.BindingSegments[setIndex]; var bindingSegments = program.BindingSegments[setIndex];
if (bindingSegments.Length == 0) if (bindingSegments.Length == 0)

View file

@ -24,6 +24,8 @@ namespace Ryujinx.Graphics.Vulkan
private HashSet<TextureStorage> _storages; private HashSet<TextureStorage> _storages;
private DescriptorSet[] _cachedDescriptorSets;
private int _cachedCommandBufferIndex; private int _cachedCommandBufferIndex;
private int _cachedSubmissionCount; private int _cachedSubmissionCount;
@ -97,6 +99,7 @@ namespace Ryujinx.Graphics.Vulkan
{ {
_cachedCommandBufferIndex = -1; _cachedCommandBufferIndex = -1;
_storages = null; _storages = null;
_cachedDescriptorSets = null;
_gd.PipelineInternal.ForceImageDirty(); _gd.PipelineInternal.ForceImageDirty();
} }
@ -175,5 +178,52 @@ namespace Ryujinx.Graphics.Vulkan
return bufferTextures; return bufferTextures;
} }
public DescriptorSet[] GetDescriptorSets(
Device device,
CommandBufferScoped cbs,
DescriptorSetTemplateUpdater templateUpdater,
ShaderCollection program,
int setIndex,
TextureView dummyTexture)
{
if (_cachedDescriptorSets != null)
{
// We still need to ensure the current command buffer holds a reference to all used textures.
if (!_isBuffer)
{
GetImageInfos(_gd, cbs, dummyTexture);
}
else
{
GetBufferViews(cbs);
}
return _cachedDescriptorSets;
}
program.UpdateDescriptorCacheCommandBufferIndex(cbs.CommandBufferIndex);
var dsc = program.GetNewDescriptorSetCollection(setIndex, out _).Get(cbs);
DescriptorSetTemplate template = program.Templates[setIndex];
DescriptorSetTemplateWriter tu = templateUpdater.Begin(template);
if (!_isBuffer)
{
tu.Push(GetImageInfos(_gd, cbs, dummyTexture));
}
else
{
tu.Push(GetBufferViews(cbs));
}
var sets = dsc.GetSets();
templateUpdater.Commit(_gd, device, sets[0]);
_cachedDescriptorSets = sets;
return sets;
}
} }
} }

View file

@ -903,6 +903,11 @@ namespace Ryujinx.Graphics.Vulkan
_descriptorSetUpdater.SetImageArray(Cbs, stage, binding, array); _descriptorSetUpdater.SetImageArray(Cbs, stage, binding, array);
} }
public void SetImageArray(ShaderStage stage, int setIndex, int binding, IImageArray array)
{
_descriptorSetUpdater.SetImageArray(Cbs, stage, setIndex, binding, array);
}
public void SetIndexBuffer(BufferRange buffer, IndexType type) public void SetIndexBuffer(BufferRange buffer, IndexType type)
{ {
if (buffer.Handle != BufferHandle.Null) if (buffer.Handle != BufferHandle.Null)
@ -1156,6 +1161,11 @@ namespace Ryujinx.Graphics.Vulkan
_descriptorSetUpdater.SetTextureArray(Cbs, stage, binding, array); _descriptorSetUpdater.SetTextureArray(Cbs, stage, binding, array);
} }
public void SetTextureArray(ShaderStage stage, int setIndex, int binding, ITextureArray array)
{
_descriptorSetUpdater.SetTextureArray(Cbs, stage, setIndex, binding, array);
}
public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers) public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers)
{ {
PauseTransformFeedbackInternal(); PauseTransformFeedbackInternal();

View file

@ -24,6 +24,8 @@ namespace Ryujinx.Graphics.Vulkan
private HashSet<TextureStorage> _storages; private HashSet<TextureStorage> _storages;
private DescriptorSet[] _cachedDescriptorSets;
private int _cachedCommandBufferIndex; private int _cachedCommandBufferIndex;
private int _cachedSubmissionCount; private int _cachedSubmissionCount;
@ -106,6 +108,7 @@ namespace Ryujinx.Graphics.Vulkan
{ {
_cachedCommandBufferIndex = -1; _cachedCommandBufferIndex = -1;
_storages = null; _storages = null;
_cachedDescriptorSets = null;
_gd.PipelineInternal.ForceTextureDirty(); _gd.PipelineInternal.ForceTextureDirty();
} }
@ -190,5 +193,53 @@ namespace Ryujinx.Graphics.Vulkan
return bufferTextures; return bufferTextures;
} }
public DescriptorSet[] GetDescriptorSets(
Device device,
CommandBufferScoped cbs,
DescriptorSetTemplateUpdater templateUpdater,
ShaderCollection program,
int setIndex,
TextureView dummyTexture,
SamplerHolder dummySampler)
{
if (_cachedDescriptorSets != null)
{
// We still need to ensure the current command buffer holds a reference to all used textures.
if (!_isBuffer)
{
GetImageInfos(_gd, cbs, dummyTexture, dummySampler);
}
else
{
GetBufferViews(cbs);
}
return _cachedDescriptorSets;
}
program.UpdateDescriptorCacheCommandBufferIndex(cbs.CommandBufferIndex);
var dsc = program.GetNewDescriptorSetCollection(setIndex, out _).Get(cbs);
DescriptorSetTemplate template = program.Templates[setIndex];
DescriptorSetTemplateWriter tu = templateUpdater.Begin(template);
if (!_isBuffer)
{
tu.Push(GetImageInfos(_gd, cbs, dummyTexture, dummySampler));
}
else
{
tu.Push(GetBufferViews(cbs));
}
var sets = dsc.GetSets();
templateUpdater.Commit(_gd, device, sets[0]);
_cachedDescriptorSets = sets;
return sets;
}
} }
} }