aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Vulkan/TextureArray.cs
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2024-04-07 18:25:55 -0300
committerGitHub <noreply@github.com>2024-04-07 18:25:55 -0300
commit3e6e0e4afaa3c3ffb118cb17b61feb16966a7eeb (patch)
treea4652499c089b0853e39c382cad82a9db4d6ad08 /src/Ryujinx.Graphics.Vulkan/TextureArray.cs
parent808803d97a0c06809bf000687c252f960048fcf0 (diff)
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
Diffstat (limited to 'src/Ryujinx.Graphics.Vulkan/TextureArray.cs')
-rw-r--r--src/Ryujinx.Graphics.Vulkan/TextureArray.cs194
1 files changed, 194 insertions, 0 deletions
diff --git a/src/Ryujinx.Graphics.Vulkan/TextureArray.cs b/src/Ryujinx.Graphics.Vulkan/TextureArray.cs
new file mode 100644
index 00000000..6ef9087b
--- /dev/null
+++ b/src/Ryujinx.Graphics.Vulkan/TextureArray.cs
@@ -0,0 +1,194 @@
+using Ryujinx.Graphics.GAL;
+using Silk.NET.Vulkan;
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.Graphics.Vulkan
+{
+ class TextureArray : ITextureArray
+ {
+ private readonly VulkanRenderer _gd;
+
+ private struct TextureRef
+ {
+ public TextureStorage Storage;
+ public Auto<DisposableImageView> View;
+ public Auto<DisposableSampler> Sampler;
+ }
+
+ private readonly TextureRef[] _textureRefs;
+ private readonly TextureBuffer[] _bufferTextureRefs;
+
+ private readonly DescriptorImageInfo[] _textures;
+ private readonly BufferView[] _bufferTextures;
+
+ private HashSet<TextureStorage> _storages;
+
+ private int _cachedCommandBufferIndex;
+ private int _cachedSubmissionCount;
+
+ private readonly bool _isBuffer;
+
+ public bool Bound;
+
+ public TextureArray(VulkanRenderer gd, int size, bool isBuffer)
+ {
+ _gd = gd;
+
+ if (isBuffer)
+ {
+ _bufferTextureRefs = new TextureBuffer[size];
+ _bufferTextures = new BufferView[size];
+ }
+ else
+ {
+ _textureRefs = new TextureRef[size];
+ _textures = new DescriptorImageInfo[size];
+ }
+
+ _storages = null;
+
+ _cachedCommandBufferIndex = -1;
+ _cachedSubmissionCount = 0;
+
+ _isBuffer = isBuffer;
+ }
+
+ public void SetSamplers(int index, ISampler[] samplers)
+ {
+ for (int i = 0; i < samplers.Length; i++)
+ {
+ ISampler sampler = samplers[i];
+
+ if (sampler is SamplerHolder samplerHolder)
+ {
+ _textureRefs[index + i].Sampler = samplerHolder.GetSampler();
+ }
+ else
+ {
+ _textureRefs[index + i].Sampler = default;
+ }
+ }
+
+ SetDirty();
+ }
+
+ public void SetTextures(int index, ITexture[] textures)
+ {
+ for (int i = 0; i < textures.Length; i++)
+ {
+ ITexture texture = textures[i];
+
+ if (texture is TextureBuffer textureBuffer)
+ {
+ _bufferTextureRefs[index + i] = textureBuffer;
+ }
+ else if (texture is TextureView view)
+ {
+ _textureRefs[index + i].Storage = view.Storage;
+ _textureRefs[index + i].View = view.GetImageView();
+ }
+ else if (!_isBuffer)
+ {
+ _textureRefs[index + i].Storage = null;
+ _textureRefs[index + i].View = default;
+ }
+ else
+ {
+ _bufferTextureRefs[index + i] = null;
+ }
+ }
+
+ SetDirty();
+ }
+
+ private void SetDirty()
+ {
+ _cachedCommandBufferIndex = -1;
+ _storages = null;
+
+ _gd.PipelineInternal.ForceTextureDirty();
+ }
+
+ public void QueueWriteToReadBarriers(CommandBufferScoped cbs, PipelineStageFlags stageFlags)
+ {
+ HashSet<TextureStorage> storages = _storages;
+
+ if (storages == null)
+ {
+ storages = new HashSet<TextureStorage>();
+
+ for (int index = 0; index < _textureRefs.Length; index++)
+ {
+ if (_textureRefs[index].Storage != null)
+ {
+ storages.Add(_textureRefs[index].Storage);
+ }
+ }
+
+ _storages = storages;
+ }
+
+ foreach (TextureStorage storage in storages)
+ {
+ storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stageFlags);
+ }
+ }
+
+ public ReadOnlySpan<DescriptorImageInfo> GetImageInfos(VulkanRenderer gd, CommandBufferScoped cbs, TextureView dummyTexture, SamplerHolder dummySampler)
+ {
+ int submissionCount = gd.CommandBufferPool.GetSubmissionCount(cbs.CommandBufferIndex);
+
+ Span<DescriptorImageInfo> textures = _textures;
+
+ if (cbs.CommandBufferIndex == _cachedCommandBufferIndex && submissionCount == _cachedSubmissionCount)
+ {
+ return textures;
+ }
+
+ _cachedCommandBufferIndex = cbs.CommandBufferIndex;
+ _cachedSubmissionCount = submissionCount;
+
+ for (int i = 0; i < textures.Length; i++)
+ {
+ ref var texture = ref textures[i];
+ ref var refs = ref _textureRefs[i];
+
+ if (i > 0 && _textureRefs[i - 1].View == refs.View && _textureRefs[i - 1].Sampler == refs.Sampler)
+ {
+ texture = textures[i - 1];
+
+ continue;
+ }
+
+ texture.ImageLayout = ImageLayout.General;
+ texture.ImageView = refs.View?.Get(cbs).Value ?? default;
+ texture.Sampler = refs.Sampler?.Get(cbs).Value ?? default;
+
+ if (texture.ImageView.Handle == 0)
+ {
+ texture.ImageView = dummyTexture.GetImageView().Get(cbs).Value;
+ }
+
+ if (texture.Sampler.Handle == 0)
+ {
+ texture.Sampler = dummySampler.GetSampler().Get(cbs).Value;
+ }
+ }
+
+ return textures;
+ }
+
+ public ReadOnlySpan<BufferView> GetBufferViews(CommandBufferScoped cbs)
+ {
+ Span<BufferView> bufferTextures = _bufferTextures;
+
+ for (int i = 0; i < bufferTextures.Length; i++)
+ {
+ bufferTextures[i] = _bufferTextureRefs[i]?.GetBufferView(cbs, false) ?? default;
+ }
+
+ return bufferTextures;
+ }
+ }
+}