aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Vulkan
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.Graphics.Vulkan')
-rw-r--r--src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs170
-rw-r--r--src/Ryujinx.Graphics.Vulkan/ImageArray.cs75
-rw-r--r--src/Ryujinx.Graphics.Vulkan/PipelineBase.cs16
-rw-r--r--src/Ryujinx.Graphics.Vulkan/PipelineLayoutCacheEntry.cs80
-rw-r--r--src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs10
-rw-r--r--src/Ryujinx.Graphics.Vulkan/TextureArray.cs76
-rw-r--r--src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs6
7 files changed, 385 insertions, 48 deletions
diff --git a/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs b/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs
index a0010e66..382f88d0 100644
--- a/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs
+++ b/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs
@@ -69,17 +69,7 @@ namespace Ryujinx.Graphics.Vulkan
}
}
- private record struct ArrayRef<T>
- {
- public ShaderStage Stage;
- public T Array;
-
- public ArrayRef(ShaderStage stage, T array)
- {
- Stage = stage;
- Array = array;
- }
- }
+ private readonly record struct ArrayRef<T>(ShaderStage Stage, T Array);
private readonly VulkanRenderer _gd;
private readonly Device _device;
@@ -97,6 +87,9 @@ namespace Ryujinx.Graphics.Vulkan
private ArrayRef<TextureArray>[] _textureArrayRefs;
private ArrayRef<ImageArray>[] _imageArrayRefs;
+ private ArrayRef<TextureArray>[] _textureArrayExtraRefs;
+ private ArrayRef<ImageArray>[] _imageArrayExtraRefs;
+
private readonly DescriptorBufferInfo[] _uniformBuffers;
private readonly DescriptorBufferInfo[] _storageBuffers;
private readonly DescriptorImageInfo[] _textures;
@@ -152,6 +145,9 @@ namespace Ryujinx.Graphics.Vulkan
_textureArrayRefs = Array.Empty<ArrayRef<TextureArray>>();
_imageArrayRefs = Array.Empty<ArrayRef<ImageArray>>();
+ _textureArrayExtraRefs = Array.Empty<ArrayRef<TextureArray>>();
+ _imageArrayExtraRefs = Array.Empty<ArrayRef<ImageArray>>();
+
_uniformBuffers = new DescriptorBufferInfo[Constants.MaxUniformBufferBindings];
_storageBuffers = new DescriptorBufferInfo[Constants.MaxStorageBufferBindings];
_textures = new DescriptorImageInfo[Constants.MaxTexturesPerStage];
@@ -495,25 +491,39 @@ namespace Ryujinx.Graphics.Vulkan
public void SetTextureArray(CommandBufferScoped cbs, ShaderStage stage, int binding, ITextureArray array)
{
- if (_textureArrayRefs.Length <= binding)
- {
- Array.Resize(ref _textureArrayRefs, binding + ArrayGrowthSize);
- }
+ ref ArrayRef<TextureArray> arrayRef = ref GetArrayRef(ref _textureArrayRefs, binding, ArrayGrowthSize);
- if (_textureArrayRefs[binding].Stage != stage || _textureArrayRefs[binding].Array != array)
+ if (arrayRef.Stage != stage || arrayRef.Array != array)
{
- if (_textureArrayRefs[binding].Array != null)
+ arrayRef.Array?.DecrementBindCount();
+
+ if (array is TextureArray textureArray)
{
- _textureArrayRefs[binding].Array.Bound = false;
+ textureArray.IncrementBindCount();
+ textureArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags());
}
+ arrayRef = new ArrayRef<TextureArray>(stage, array as TextureArray);
+
+ SignalDirty(DirtyFlags.Texture);
+ }
+ }
+
+ public void SetTextureArraySeparate(CommandBufferScoped cbs, ShaderStage stage, int setIndex, ITextureArray array)
+ {
+ ref ArrayRef<TextureArray> arrayRef = ref GetArrayRef(ref _textureArrayExtraRefs, setIndex - PipelineBase.DescriptorSetLayouts);
+
+ if (arrayRef.Stage != stage || arrayRef.Array != array)
+ {
+ arrayRef.Array?.DecrementBindCount();
+
if (array is TextureArray textureArray)
{
- textureArray.Bound = true;
+ textureArray.IncrementBindCount();
textureArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags());
}
- _textureArrayRefs[binding] = new ArrayRef<TextureArray>(stage, array as TextureArray);
+ arrayRef = new ArrayRef<TextureArray>(stage, array as TextureArray);
SignalDirty(DirtyFlags.Texture);
}
@@ -521,30 +531,56 @@ namespace Ryujinx.Graphics.Vulkan
public void SetImageArray(CommandBufferScoped cbs, ShaderStage stage, int binding, IImageArray array)
{
- if (_imageArrayRefs.Length <= binding)
- {
- Array.Resize(ref _imageArrayRefs, binding + ArrayGrowthSize);
- }
+ ref ArrayRef<ImageArray> arrayRef = ref GetArrayRef(ref _imageArrayRefs, binding, ArrayGrowthSize);
- if (_imageArrayRefs[binding].Stage != stage || _imageArrayRefs[binding].Array != array)
+ if (arrayRef.Stage != stage || arrayRef.Array != array)
{
- if (_imageArrayRefs[binding].Array != null)
+ arrayRef.Array?.DecrementBindCount();
+
+ if (array is ImageArray imageArray)
{
- _imageArrayRefs[binding].Array.Bound = false;
+ imageArray.IncrementBindCount();
+ imageArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags());
}
+ arrayRef = new ArrayRef<ImageArray>(stage, array as ImageArray);
+
+ SignalDirty(DirtyFlags.Image);
+ }
+ }
+
+ public void SetImageArraySeparate(CommandBufferScoped cbs, ShaderStage stage, int setIndex, IImageArray array)
+ {
+ ref ArrayRef<ImageArray> arrayRef = ref GetArrayRef(ref _imageArrayExtraRefs, setIndex - PipelineBase.DescriptorSetLayouts);
+
+ if (arrayRef.Stage != stage || arrayRef.Array != array)
+ {
+ arrayRef.Array?.DecrementBindCount();
+
if (array is ImageArray imageArray)
{
- imageArray.Bound = true;
+ imageArray.IncrementBindCount();
imageArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags());
}
- _imageArrayRefs[binding] = new ArrayRef<ImageArray>(stage, array as ImageArray);
+ arrayRef = new ArrayRef<ImageArray>(stage, array as ImageArray);
SignalDirty(DirtyFlags.Image);
}
}
+ private static ref ArrayRef<T> GetArrayRef<T>(ref ArrayRef<T>[] array, int index, int growthSize = 1)
+ {
+ ArgumentOutOfRangeException.ThrowIfNegative(index);
+
+ if (array.Length <= index)
+ {
+ Array.Resize(ref array, index + growthSize);
+ }
+
+ return ref array[index];
+ }
+
public void SetUniformBuffers(CommandBuffer commandBuffer, ReadOnlySpan<BufferAssignment> buffers)
{
for (int i = 0; i < buffers.Length; i++)
@@ -594,31 +630,40 @@ namespace Ryujinx.Graphics.Vulkan
return;
}
+ var program = _program;
+
if (_dirty.HasFlag(DirtyFlags.Uniform))
{
- if (_program.UsePushDescriptors)
+ if (program.UsePushDescriptors)
{
- UpdateAndBindUniformBufferPd(cbs, pbp);
+ UpdateAndBindUniformBufferPd(cbs);
}
else
{
- UpdateAndBind(cbs, PipelineBase.UniformSetIndex, pbp);
+ UpdateAndBind(cbs, program, PipelineBase.UniformSetIndex, pbp);
}
}
if (_dirty.HasFlag(DirtyFlags.Storage))
{
- UpdateAndBind(cbs, PipelineBase.StorageSetIndex, pbp);
+ UpdateAndBind(cbs, program, PipelineBase.StorageSetIndex, pbp);
}
if (_dirty.HasFlag(DirtyFlags.Texture))
{
- UpdateAndBind(cbs, PipelineBase.TextureSetIndex, pbp);
+ UpdateAndBind(cbs, program, PipelineBase.TextureSetIndex, pbp);
}
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.
+
+ BindExtraSets(cbs, program, pbp);
}
_dirty = DirtyFlags.None;
@@ -658,9 +703,8 @@ namespace Ryujinx.Graphics.Vulkan
}
[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];
if (bindingSegments.Length == 0)
@@ -869,7 +913,7 @@ namespace Ryujinx.Graphics.Vulkan
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void UpdateAndBindUniformBufferPd(CommandBufferScoped cbs, PipelineBindPoint pbp)
+ private void UpdateAndBindUniformBufferPd(CommandBufferScoped cbs)
{
int sequence = _pdSequence;
var bindingSegments = _program.BindingSegments[PipelineBase.UniformSetIndex];
@@ -933,6 +977,56 @@ namespace Ryujinx.Graphics.Vulkan
}
}
+ private void BindExtraSets(CommandBufferScoped cbs, ShaderCollection program, PipelineBindPoint pbp)
+ {
+ 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);
+ }
+ }
+ }
+ }
+
public void SignalCommandBufferChange()
{
_updateDescriptorCacheCbIndex = true;
diff --git a/src/Ryujinx.Graphics.Vulkan/ImageArray.cs b/src/Ryujinx.Graphics.Vulkan/ImageArray.cs
index 38a5b6b4..3c7f321f 100644
--- a/src/Ryujinx.Graphics.Vulkan/ImageArray.cs
+++ b/src/Ryujinx.Graphics.Vulkan/ImageArray.cs
@@ -2,6 +2,7 @@ using Ryujinx.Graphics.GAL;
using Silk.NET.Vulkan;
using System;
using System.Collections.Generic;
+using System.Diagnostics;
namespace Ryujinx.Graphics.Vulkan
{
@@ -24,12 +25,18 @@ namespace Ryujinx.Graphics.Vulkan
private HashSet<TextureStorage> _storages;
+ private DescriptorSet[] _cachedDescriptorSets;
+
private int _cachedCommandBufferIndex;
private int _cachedSubmissionCount;
+ private ShaderCollection _cachedDscProgram;
+ private int _cachedDscSetIndex;
+ private int _cachedDscIndex;
+
private readonly bool _isBuffer;
- public bool Bound;
+ private int _bindCount;
public ImageArray(VulkanRenderer gd, int size, bool isBuffer)
{
@@ -97,8 +104,12 @@ namespace Ryujinx.Graphics.Vulkan
{
_cachedCommandBufferIndex = -1;
_storages = null;
+ _cachedDescriptorSets = null;
- _gd.PipelineInternal.ForceImageDirty();
+ if (_bindCount != 0)
+ {
+ _gd.PipelineInternal.ForceImageDirty();
+ }
}
public void QueueWriteToReadBarriers(CommandBufferScoped cbs, PipelineStageFlags stageFlags)
@@ -175,5 +186,65 @@ namespace Ryujinx.Graphics.Vulkan
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;
+ }
+
+ _cachedDscProgram?.ReleaseManualDescriptorSetCollection(_cachedDscSetIndex, _cachedDscIndex);
+ var dsc = program.GetNewManualDescriptorSetCollection(cbs.CommandBufferIndex, setIndex, out _cachedDscIndex).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;
+ _cachedDscProgram = program;
+ _cachedDscSetIndex = setIndex;
+
+ return sets;
+ }
+
+ public void IncrementBindCount()
+ {
+ _bindCount++;
+ }
+
+ public void DecrementBindCount()
+ {
+ int newBindCount = --_bindCount;
+ Debug.Assert(newBindCount >= 0);
+ }
}
}
diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs
index 3776e2f6..918de59b 100644
--- a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs
+++ b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs
@@ -751,14 +751,12 @@ namespace Ryujinx.Graphics.Vulkan
_vertexBufferUpdater.Commit(Cbs);
}
-#pragma warning disable CA1822 // Mark member as static
public void SetAlphaTest(bool enable, float reference, CompareOp op)
{
// This is currently handled using shader specialization, as Vulkan does not support alpha test.
// In the future, we may want to use this to write the reference value into the support buffer,
// to avoid creating one version of the shader per reference value used.
}
-#pragma warning restore CA1822
public void SetBlendState(AdvancedBlendDescriptor blend)
{
@@ -903,6 +901,11 @@ namespace Ryujinx.Graphics.Vulkan
_descriptorSetUpdater.SetImageArray(Cbs, stage, binding, array);
}
+ public void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array)
+ {
+ _descriptorSetUpdater.SetImageArraySeparate(Cbs, stage, setIndex, array);
+ }
+
public void SetIndexBuffer(BufferRange buffer, IndexType type)
{
if (buffer.Handle != BufferHandle.Null)
@@ -945,7 +948,6 @@ namespace Ryujinx.Graphics.Vulkan
// TODO: Default levels (likely needs emulation on shaders?)
}
-#pragma warning disable CA1822 // Mark member as static
public void SetPointParameters(float size, bool isProgramPointSize, bool enablePointSprite, Origin origin)
{
// TODO.
@@ -955,7 +957,6 @@ namespace Ryujinx.Graphics.Vulkan
{
// TODO.
}
-#pragma warning restore CA1822
public void SetPrimitiveRestart(bool enable, int index)
{
@@ -1156,6 +1157,11 @@ namespace Ryujinx.Graphics.Vulkan
_descriptorSetUpdater.SetTextureArray(Cbs, stage, binding, array);
}
+ public void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array)
+ {
+ _descriptorSetUpdater.SetTextureArraySeparate(Cbs, stage, setIndex, array);
+ }
+
public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers)
{
PauseTransformFeedbackInternal();
@@ -1186,12 +1192,10 @@ namespace Ryujinx.Graphics.Vulkan
_descriptorSetUpdater.SetUniformBuffers(CommandBuffer, buffers);
}
-#pragma warning disable CA1822 // Mark member as static
public void SetUserClipDistance(int index, bool enableClip)
{
// TODO.
}
-#pragma warning restore CA1822
public void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs)
{
diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineLayoutCacheEntry.cs b/src/Ryujinx.Graphics.Vulkan/PipelineLayoutCacheEntry.cs
index fb1f0a5f..7d0948d6 100644
--- a/src/Ryujinx.Graphics.Vulkan/PipelineLayoutCacheEntry.cs
+++ b/src/Ryujinx.Graphics.Vulkan/PipelineLayoutCacheEntry.cs
@@ -3,6 +3,7 @@ using Silk.NET.Vulkan;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
+using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Vulkan
{
@@ -27,6 +28,24 @@ namespace Ryujinx.Graphics.Vulkan
private int _dsLastCbIndex;
private int _dsLastSubmissionCount;
+ private struct ManualDescriptorSetEntry
+ {
+ public Auto<DescriptorSetCollection> DescriptorSet;
+ public int CbIndex;
+ public int CbSubmissionCount;
+ public bool InUse;
+
+ public ManualDescriptorSetEntry(Auto<DescriptorSetCollection> descriptorSet, int cbIndex, int cbSubmissionCount, bool inUse)
+ {
+ DescriptorSet = descriptorSet;
+ CbIndex = cbIndex;
+ CbSubmissionCount = cbSubmissionCount;
+ InUse = inUse;
+ }
+ }
+
+ private readonly List<ManualDescriptorSetEntry>[] _manualDsCache;
+
private readonly Dictionary<long, DescriptorSetTemplate> _pdTemplates;
private readonly ResourceDescriptorCollection _pdDescriptors;
private long _lastPdUsage;
@@ -50,6 +69,7 @@ namespace Ryujinx.Graphics.Vulkan
}
_dsCacheCursor = new int[setsCount];
+ _manualDsCache = new List<ManualDescriptorSetEntry>[setsCount];
}
public PipelineLayoutCacheEntry(
@@ -124,6 +144,51 @@ namespace Ryujinx.Graphics.Vulkan
return list[index];
}
+ public Auto<DescriptorSetCollection> GetNewManualDescriptorSetCollection(int commandBufferIndex, int setIndex, out int cacheIndex)
+ {
+ int submissionCount = _gd.CommandBufferPool.GetSubmissionCount(commandBufferIndex);
+
+ var list = _manualDsCache[setIndex] ??= new();
+ var span = CollectionsMarshal.AsSpan(list);
+
+ for (int index = 0; index < span.Length; index++)
+ {
+ ref ManualDescriptorSetEntry entry = ref span[index];
+
+ if (!entry.InUse && (entry.CbIndex != commandBufferIndex || entry.CbSubmissionCount != submissionCount))
+ {
+ entry.InUse = true;
+ entry.CbIndex = commandBufferIndex;
+ entry.CbSubmissionCount = submissionCount;
+
+ cacheIndex = index;
+
+ return entry.DescriptorSet;
+ }
+ }
+
+ var dsc = _descriptorSetManager.AllocateDescriptorSet(
+ _gd.Api,
+ DescriptorSetLayouts[setIndex],
+ _poolSizes[setIndex],
+ setIndex,
+ _consumedDescriptorsPerSet[setIndex],
+ false);
+
+ cacheIndex = list.Count;
+ list.Add(new ManualDescriptorSetEntry(dsc, commandBufferIndex, submissionCount, inUse: true));
+
+ return dsc;
+ }
+
+ public void ReleaseManualDescriptorSetCollection(int setIndex, int cacheIndex)
+ {
+ var list = _manualDsCache[setIndex];
+ var span = CollectionsMarshal.AsSpan(list);
+
+ span[cacheIndex].InUse = false;
+ }
+
private static Span<DescriptorPoolSize> GetDescriptorPoolSizes(Span<DescriptorPoolSize> output, ResourceDescriptorCollection setDescriptor, uint multiplier)
{
int count = 0;
@@ -204,6 +269,21 @@ namespace Ryujinx.Graphics.Vulkan
}
}
+ for (int i = 0; i < _manualDsCache.Length; i++)
+ {
+ if (_manualDsCache[i] == null)
+ {
+ continue;
+ }
+
+ for (int j = 0; j < _manualDsCache[i].Count; j++)
+ {
+ _manualDsCache[i][j].DescriptorSet.Dispose();
+ }
+
+ _manualDsCache[i].Clear();
+ }
+
_gd.Api.DestroyPipelineLayout(_device, PipelineLayout, null);
for (int i = 0; i < DescriptorSetLayouts.Length; i++)
diff --git a/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs b/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs
index 17854698..f2d648a5 100644
--- a/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs
+++ b/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs
@@ -604,6 +604,16 @@ namespace Ryujinx.Graphics.Vulkan
return _plce.GetNewDescriptorSetCollection(setIndex, out isNew);
}
+ public Auto<DescriptorSetCollection> GetNewManualDescriptorSetCollection(int commandBufferIndex, int setIndex, out int cacheIndex)
+ {
+ return _plce.GetNewManualDescriptorSetCollection(commandBufferIndex, setIndex, out cacheIndex);
+ }
+
+ public void ReleaseManualDescriptorSetCollection(int setIndex, int cacheIndex)
+ {
+ _plce.ReleaseManualDescriptorSetCollection(setIndex, cacheIndex);
+ }
+
public bool HasSameLayout(ShaderCollection other)
{
return other != null && _plce == other._plce;
diff --git a/src/Ryujinx.Graphics.Vulkan/TextureArray.cs b/src/Ryujinx.Graphics.Vulkan/TextureArray.cs
index 6ef9087b..fe834225 100644
--- a/src/Ryujinx.Graphics.Vulkan/TextureArray.cs
+++ b/src/Ryujinx.Graphics.Vulkan/TextureArray.cs
@@ -2,6 +2,7 @@ using Ryujinx.Graphics.GAL;
using Silk.NET.Vulkan;
using System;
using System.Collections.Generic;
+using System.Diagnostics;
namespace Ryujinx.Graphics.Vulkan
{
@@ -24,12 +25,18 @@ namespace Ryujinx.Graphics.Vulkan
private HashSet<TextureStorage> _storages;
+ private DescriptorSet[] _cachedDescriptorSets;
+
private int _cachedCommandBufferIndex;
private int _cachedSubmissionCount;
+ private ShaderCollection _cachedDscProgram;
+ private int _cachedDscSetIndex;
+ private int _cachedDscIndex;
+
private readonly bool _isBuffer;
- public bool Bound;
+ private int _bindCount;
public TextureArray(VulkanRenderer gd, int size, bool isBuffer)
{
@@ -106,8 +113,12 @@ namespace Ryujinx.Graphics.Vulkan
{
_cachedCommandBufferIndex = -1;
_storages = null;
+ _cachedDescriptorSets = null;
- _gd.PipelineInternal.ForceTextureDirty();
+ if (_bindCount != 0)
+ {
+ _gd.PipelineInternal.ForceTextureDirty();
+ }
}
public void QueueWriteToReadBarriers(CommandBufferScoped cbs, PipelineStageFlags stageFlags)
@@ -190,5 +201,66 @@ namespace Ryujinx.Graphics.Vulkan
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;
+ }
+
+ _cachedDscProgram?.ReleaseManualDescriptorSetCollection(_cachedDscSetIndex, _cachedDscIndex);
+ var dsc = program.GetNewManualDescriptorSetCollection(cbs.CommandBufferIndex, setIndex, out _cachedDscIndex).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;
+ _cachedDscProgram = program;
+ _cachedDscSetIndex = setIndex;
+
+ return sets;
+ }
+
+ public void IncrementBindCount()
+ {
+ _bindCount++;
+ }
+
+ public void DecrementBindCount()
+ {
+ int newBindCount = --_bindCount;
+ Debug.Assert(newBindCount >= 0);
+ }
}
}
diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs
index 175d5e3e..86a347e0 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,