Add support for large sampler arrays on Vulkan (#6489)

* Add support for large sampler arrays on Vulkan

* Shader cache version bump

* Format whitespace

* Move DescriptorSetManager to PipelineLayoutCacheEntry to allow different pool sizes per layout

* Handle array textures with different types on the same buffer

* Somewhat better caching system

* Avoid useless buffer data modification checks

* Move redundant bindings update checking to the backend

* Fix an issue where texture arrays would get the same bindings across stages on Vulkan

* Backport some fixes from part 2

* Fix typo

* PR feedback

* Format whitespace

* Add some missing XML docs
This commit is contained in:
gdkchan 2024-04-07 18:25:55 -03:00 committed by GitHub
parent 808803d97a
commit 3e6e0e4afa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
83 changed files with 3263 additions and 955 deletions

View file

@ -1,10 +1,12 @@
using Ryujinx.Graphics.GAL.Multithreading.Commands;
using Ryujinx.Graphics.GAL.Multithreading.Commands.Buffer;
using Ryujinx.Graphics.GAL.Multithreading.Commands.CounterEvent;
using Ryujinx.Graphics.GAL.Multithreading.Commands.ImageArray;
using Ryujinx.Graphics.GAL.Multithreading.Commands.Program;
using Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer;
using Ryujinx.Graphics.GAL.Multithreading.Commands.Sampler;
using Ryujinx.Graphics.GAL.Multithreading.Commands.Texture;
using Ryujinx.Graphics.GAL.Multithreading.Commands.TextureArray;
using Ryujinx.Graphics.GAL.Multithreading.Commands.Window;
using System;
using System.Linq;
@ -46,10 +48,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading
Register<CreateBufferAccessCommand>(CommandType.CreateBufferAccess);
Register<CreateBufferSparseCommand>(CommandType.CreateBufferSparse);
Register<CreateHostBufferCommand>(CommandType.CreateHostBuffer);
Register<CreateImageArrayCommand>(CommandType.CreateImageArray);
Register<CreateProgramCommand>(CommandType.CreateProgram);
Register<CreateSamplerCommand>(CommandType.CreateSampler);
Register<CreateSyncCommand>(CommandType.CreateSync);
Register<CreateTextureCommand>(CommandType.CreateTexture);
Register<CreateTextureArrayCommand>(CommandType.CreateTextureArray);
Register<GetCapabilitiesCommand>(CommandType.GetCapabilities);
Register<PreFrameCommand>(CommandType.PreFrame);
Register<ReportCounterCommand>(CommandType.ReportCounter);
@ -63,6 +67,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading
Register<CounterEventDisposeCommand>(CommandType.CounterEventDispose);
Register<CounterEventFlushCommand>(CommandType.CounterEventFlush);
Register<ImageArraySetFormatsCommand>(CommandType.ImageArraySetFormats);
Register<ImageArraySetImagesCommand>(CommandType.ImageArraySetImages);
Register<ProgramDisposeCommand>(CommandType.ProgramDispose);
Register<ProgramGetBinaryCommand>(CommandType.ProgramGetBinary);
Register<ProgramCheckLinkCommand>(CommandType.ProgramCheckLink);
@ -82,6 +89,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading
Register<TextureSetDataSliceRegionCommand>(CommandType.TextureSetDataSliceRegion);
Register<TextureSetStorageCommand>(CommandType.TextureSetStorage);
Register<TextureArraySetSamplersCommand>(CommandType.TextureArraySetSamplers);
Register<TextureArraySetTexturesCommand>(CommandType.TextureArraySetTextures);
Register<WindowPresentCommand>(CommandType.WindowPresent);
Register<BarrierCommand>(CommandType.Barrier);
@ -114,6 +124,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
Register<SetTransformFeedbackBuffersCommand>(CommandType.SetTransformFeedbackBuffers);
Register<SetUniformBuffersCommand>(CommandType.SetUniformBuffers);
Register<SetImageCommand>(CommandType.SetImage);
Register<SetImageArrayCommand>(CommandType.SetImageArray);
Register<SetIndexBufferCommand>(CommandType.SetIndexBuffer);
Register<SetLineParametersCommand>(CommandType.SetLineParameters);
Register<SetLogicOpStateCommand>(CommandType.SetLogicOpState);
@ -130,6 +141,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
Register<SetScissorsCommand>(CommandType.SetScissor);
Register<SetStencilTestCommand>(CommandType.SetStencilTest);
Register<SetTextureAndSamplerCommand>(CommandType.SetTextureAndSampler);
Register<SetTextureArrayCommand>(CommandType.SetTextureArray);
Register<SetUserClipDistanceCommand>(CommandType.SetUserClipDistance);
Register<SetVertexAttribsCommand>(CommandType.SetVertexAttribs);
Register<SetVertexBuffersCommand>(CommandType.SetVertexBuffers);

View file

@ -7,10 +7,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading
CreateBufferAccess,
CreateBufferSparse,
CreateHostBuffer,
CreateImageArray,
CreateProgram,
CreateSampler,
CreateSync,
CreateTexture,
CreateTextureArray,
GetCapabilities,
Unused,
PreFrame,
@ -25,6 +27,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading
CounterEventDispose,
CounterEventFlush,
ImageArraySetFormats,
ImageArraySetImages,
ProgramDispose,
ProgramGetBinary,
ProgramCheckLink,
@ -44,6 +49,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading
TextureSetDataSliceRegion,
TextureSetStorage,
TextureArraySetSamplers,
TextureArraySetTextures,
WindowPresent,
Barrier,
@ -76,6 +84,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
SetTransformFeedbackBuffers,
SetUniformBuffers,
SetImage,
SetImageArray,
SetIndexBuffer,
SetLineParameters,
SetLogicOpState,
@ -92,6 +101,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
SetScissor,
SetStencilTest,
SetTextureAndSampler,
SetTextureArray,
SetUserClipDistance,
SetVertexAttribs,
SetVertexBuffers,

View file

@ -0,0 +1,26 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.ImageArray
{
struct ImageArraySetFormatsCommand : IGALCommand, IGALCommand<ImageArraySetFormatsCommand>
{
public readonly CommandType CommandType => CommandType.ImageArraySetFormats;
private TableRef<ThreadedImageArray> _imageArray;
private int _index;
private TableRef<Format[]> _imageFormats;
public void Set(TableRef<ThreadedImageArray> imageArray, int index, TableRef<Format[]> imageFormats)
{
_imageArray = imageArray;
_index = index;
_imageFormats = imageFormats;
}
public static void Run(ref ImageArraySetFormatsCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ThreadedImageArray imageArray = command._imageArray.Get(threaded);
imageArray.Base.SetFormats(command._index, command._imageFormats.Get(threaded));
}
}
}

View file

@ -0,0 +1,27 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
using System.Linq;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.ImageArray
{
struct ImageArraySetImagesCommand : IGALCommand, IGALCommand<ImageArraySetImagesCommand>
{
public readonly CommandType CommandType => CommandType.ImageArraySetImages;
private TableRef<ThreadedImageArray> _imageArray;
private int _index;
private TableRef<ITexture[]> _images;
public void Set(TableRef<ThreadedImageArray> imageArray, int index, TableRef<ITexture[]> images)
{
_imageArray = imageArray;
_index = index;
_images = images;
}
public static void Run(ref ImageArraySetImagesCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ThreadedImageArray imageArray = command._imageArray.Get(threaded);
imageArray.Base.SetImages(command._index, command._images.Get(threaded).Select(texture => ((ThreadedTexture)texture)?.Base).ToArray());
}
}
}

View file

@ -0,0 +1,25 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
{
struct CreateImageArrayCommand : IGALCommand, IGALCommand<CreateImageArrayCommand>
{
public readonly CommandType CommandType => CommandType.CreateImageArray;
private TableRef<ThreadedImageArray> _imageArray;
private int _size;
private bool _isBuffer;
public void Set(TableRef<ThreadedImageArray> imageArray, int size, bool isBuffer)
{
_imageArray = imageArray;
_size = size;
_isBuffer = isBuffer;
}
public static void Run(ref CreateImageArrayCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
command._imageArray.Get(threaded).Base = renderer.CreateImageArray(command._size, command._isBuffer);
}
}
}

View file

@ -0,0 +1,25 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
{
struct CreateTextureArrayCommand : IGALCommand, IGALCommand<CreateTextureArrayCommand>
{
public readonly CommandType CommandType => CommandType.CreateTextureArray;
private TableRef<ThreadedTextureArray> _textureArray;
private int _size;
private bool _isBuffer;
public void Set(TableRef<ThreadedTextureArray> textureArray, int size, bool isBuffer)
{
_textureArray = textureArray;
_size = size;
_isBuffer = isBuffer;
}
public static void Run(ref CreateTextureArrayCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
command._textureArray.Get(threaded).Base = renderer.CreateTextureArray(command._size, command._isBuffer);
}
}
}

View file

@ -0,0 +1,26 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
using Ryujinx.Graphics.Shader;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetImageArrayCommand : IGALCommand, IGALCommand<SetImageArrayCommand>
{
public readonly CommandType CommandType => CommandType.SetImageArray;
private ShaderStage _stage;
private int _binding;
private TableRef<IImageArray> _array;
public void Set(ShaderStage stage, int binding, TableRef<IImageArray> array)
{
_stage = stage;
_binding = binding;
_array = array;
}
public static void Run(ref SetImageArrayCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetImageArray(command._stage, command._binding, command._array.GetAs<ThreadedImageArray>(threaded)?.Base);
}
}
}

View file

@ -0,0 +1,26 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
using Ryujinx.Graphics.Shader;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetTextureArrayCommand : IGALCommand, IGALCommand<SetTextureArrayCommand>
{
public readonly CommandType CommandType => CommandType.SetTextureArray;
private ShaderStage _stage;
private int _binding;
private TableRef<ITextureArray> _array;
public void Set(ShaderStage stage, int binding, TableRef<ITextureArray> array)
{
_stage = stage;
_binding = binding;
_array = array;
}
public static void Run(ref SetTextureArrayCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetTextureArray(command._stage, command._binding, command._array.GetAs<ThreadedTextureArray>(threaded)?.Base);
}
}
}

View file

@ -0,0 +1,27 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
using System.Linq;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.TextureArray
{
struct TextureArraySetSamplersCommand : IGALCommand, IGALCommand<TextureArraySetSamplersCommand>
{
public readonly CommandType CommandType => CommandType.TextureArraySetSamplers;
private TableRef<ThreadedTextureArray> _textureArray;
private int _index;
private TableRef<ISampler[]> _samplers;
public void Set(TableRef<ThreadedTextureArray> textureArray, int index, TableRef<ISampler[]> samplers)
{
_textureArray = textureArray;
_index = index;
_samplers = samplers;
}
public static void Run(ref TextureArraySetSamplersCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ThreadedTextureArray textureArray = command._textureArray.Get(threaded);
textureArray.Base.SetSamplers(command._index, command._samplers.Get(threaded).Select(sampler => ((ThreadedSampler)sampler)?.Base).ToArray());
}
}
}

View file

@ -0,0 +1,27 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
using System.Linq;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.TextureArray
{
struct TextureArraySetTexturesCommand : IGALCommand, IGALCommand<TextureArraySetTexturesCommand>
{
public readonly CommandType CommandType => CommandType.TextureArraySetTextures;
private TableRef<ThreadedTextureArray> _textureArray;
private int _index;
private TableRef<ITexture[]> _textures;
public void Set(TableRef<ThreadedTextureArray> textureArray, int index, TableRef<ITexture[]> textures)
{
_textureArray = textureArray;
_index = index;
_textures = textures;
}
public static void Run(ref TextureArraySetTexturesCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ThreadedTextureArray textureArray = command._textureArray.Get(threaded);
textureArray.Base.SetTextures(command._index, command._textures.Get(threaded).Select(texture => ((ThreadedTexture)texture)?.Base).ToArray());
}
}
}

View file

@ -0,0 +1,36 @@
using Ryujinx.Graphics.GAL.Multithreading.Commands.ImageArray;
using Ryujinx.Graphics.GAL.Multithreading.Model;
namespace Ryujinx.Graphics.GAL.Multithreading.Resources
{
/// <summary>
/// Threaded representation of a image array.
/// </summary>
class ThreadedImageArray : IImageArray
{
private readonly ThreadedRenderer _renderer;
public IImageArray Base;
public ThreadedImageArray(ThreadedRenderer renderer)
{
_renderer = renderer;
}
private TableRef<T> Ref<T>(T reference)
{
return new TableRef<T>(_renderer, reference);
}
public void SetFormats(int index, Format[] imageFormats)
{
_renderer.New<ImageArraySetFormatsCommand>().Set(Ref(this), index, Ref(imageFormats));
_renderer.QueueCommand();
}
public void SetImages(int index, ITexture[] images)
{
_renderer.New<ImageArraySetImagesCommand>().Set(Ref(this), index, Ref(images));
_renderer.QueueCommand();
}
}
}

View file

@ -0,0 +1,37 @@
using Ryujinx.Graphics.GAL.Multithreading.Commands.TextureArray;
using Ryujinx.Graphics.GAL.Multithreading.Model;
using System.Linq;
namespace Ryujinx.Graphics.GAL.Multithreading.Resources
{
/// <summary>
/// Threaded representation of a texture and sampler array.
/// </summary>
class ThreadedTextureArray : ITextureArray
{
private readonly ThreadedRenderer _renderer;
public ITextureArray Base;
public ThreadedTextureArray(ThreadedRenderer renderer)
{
_renderer = renderer;
}
private TableRef<T> Ref<T>(T reference)
{
return new TableRef<T>(_renderer, reference);
}
public void SetSamplers(int index, ISampler[] samplers)
{
_renderer.New<TextureArraySetSamplersCommand>().Set(Ref(this), index, Ref(samplers.ToArray()));
_renderer.QueueCommand();
}
public void SetTextures(int index, ITexture[] textures)
{
_renderer.New<TextureArraySetTexturesCommand>().Set(Ref(this), index, Ref(textures.ToArray()));
_renderer.QueueCommand();
}
}
}

View file

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

View file

@ -299,6 +299,15 @@ namespace Ryujinx.Graphics.GAL.Multithreading
return handle;
}
public IImageArray CreateImageArray(int size, bool isBuffer)
{
var imageArray = new ThreadedImageArray(this);
New<CreateImageArrayCommand>().Set(Ref(imageArray), size, isBuffer);
QueueCommand();
return imageArray;
}
public IProgram CreateProgram(ShaderSource[] shaders, ShaderInfo info)
{
var program = new ThreadedProgram(this);
@ -349,6 +358,14 @@ namespace Ryujinx.Graphics.GAL.Multithreading
return texture;
}
}
public ITextureArray CreateTextureArray(int size, bool isBuffer)
{
var textureArray = new ThreadedTextureArray(this);
New<CreateTextureArrayCommand>().Set(Ref(textureArray), size, isBuffer);
QueueCommand();
return textureArray;
}
public void DeleteBuffer(BufferHandle buffer)
{