aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs')
-rw-r--r--src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs89
1 files changed, 82 insertions, 7 deletions
diff --git a/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs b/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs
index 6615d8ce..d40b201d 100644
--- a/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs
+++ b/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs
@@ -4,6 +4,7 @@ using Ryujinx.Graphics.Shader;
using Silk.NET.Vulkan;
using System;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using CompareOp = Ryujinx.Graphics.GAL.CompareOp;
using Format = Ryujinx.Graphics.GAL.Format;
using SamplerCreateInfo = Ryujinx.Graphics.GAL.SamplerCreateInfo;
@@ -61,6 +62,8 @@ namespace Ryujinx.Graphics.Vulkan
private BitMapStruct<Array2<long>> _storageSet;
private BitMapStruct<Array2<long>> _uniformMirrored;
private BitMapStruct<Array2<long>> _storageMirrored;
+ private readonly int[] _uniformSetPd;
+ private int _pdSequence = 1;
private bool _updateDescriptorCacheCbIndex;
@@ -106,6 +109,8 @@ namespace Ryujinx.Graphics.Vulkan
_bufferTextures = new BufferView[Constants.MaxTexturesPerStage];
_bufferImages = new BufferView[Constants.MaxImagesPerStage];
+ _uniformSetPd = new int[Constants.MaxUniformBufferBindings];
+
var initialImageInfo = new DescriptorImageInfo
{
ImageLayout = ImageLayout.General,
@@ -193,6 +198,7 @@ namespace Ryujinx.Graphics.Vulkan
if (BindingOverlaps(ref info, bindingOffset, offset, size))
{
_uniformSet.Clear(binding);
+ _uniformSetPd[binding] = 0;
SignalDirty(DirtyFlags.Uniform);
}
}
@@ -223,8 +229,30 @@ namespace Ryujinx.Graphics.Vulkan
});
}
- public void SetProgram(ShaderCollection program)
+ public void AdvancePdSequence()
+ {
+ if (++_pdSequence == 0)
+ {
+ _pdSequence = 1;
+ }
+ }
+
+ public void SetProgram(CommandBufferScoped cbs, ShaderCollection program, bool isBound)
{
+ if (!program.HasSameLayout(_program))
+ {
+ // When the pipeline layout changes, push descriptor bindings are invalidated.
+
+ AdvancePdSequence();
+
+ if (_gd.IsNvidiaPreTuring && !program.UsePushDescriptors && _program?.UsePushDescriptors == true && isBound)
+ {
+ // On older nvidia GPUs, we need to clear out the active push descriptor bindings when switching
+ // to normal descriptors. Keeping them bound can prevent buffers from binding properly in future.
+ ClearAndBindUniformBufferPd(cbs);
+ }
+ }
+
_program = program;
_updateDescriptorCacheCbIndex = true;
_dirty = DirtyFlags.All;
@@ -402,6 +430,7 @@ namespace Ryujinx.Graphics.Vulkan
if (!currentBufferRef.Equals(newRef) || currentInfo.Range != info.Range)
{
_uniformSet.Clear(index);
+ _uniformSetPd[index] = 0;
currentInfo = info;
currentBufferRef = newRef;
@@ -671,15 +700,19 @@ namespace Ryujinx.Graphics.Vulkan
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void UpdateAndBindUniformBufferPd(CommandBufferScoped cbs, PipelineBindPoint pbp)
{
+ int sequence = _pdSequence;
var bindingSegments = _program.BindingSegments[PipelineBase.UniformSetIndex];
var dummyBuffer = _dummyBuffer?.GetBuffer();
+ long updatedBindings = 0;
+ DescriptorSetTemplateWriter writer = _templateUpdater.Begin(32 * Unsafe.SizeOf<DescriptorBufferInfo>());
+
foreach (ResourceBindingSegment segment in bindingSegments)
{
int binding = segment.Binding;
int count = segment.Count;
- bool doUpdate = false;
+ ReadOnlySpan<DescriptorBufferInfo> uniformBuffers = _uniformBuffers;
for (int i = 0; i < count; i++)
{
@@ -688,17 +721,58 @@ namespace Ryujinx.Graphics.Vulkan
if (_uniformSet.Set(index))
{
ref BufferRef buffer = ref _uniformBufferRefs[index];
- UpdateBuffer(cbs, ref _uniformBuffers[index], ref buffer, dummyBuffer, true);
- doUpdate = true;
+
+ bool mirrored = UpdateBuffer(cbs, ref _uniformBuffers[index], ref buffer, dummyBuffer, true);
+
+ _uniformMirrored.Set(index, mirrored);
+ }
+
+ if (_uniformSetPd[index] != sequence)
+ {
+ // Need to set this push descriptor (even if the buffer binding has not changed)
+
+ _uniformSetPd[index] = sequence;
+ updatedBindings |= 1L << index;
+
+ writer.Push(MemoryMarshal.CreateReadOnlySpan(ref _uniformBuffers[index], 1));
}
}
+ }
+
+ if (updatedBindings > 0)
+ {
+ DescriptorSetTemplate template = _program.GetPushDescriptorTemplate(updatedBindings);
+ _templateUpdater.CommitPushDescriptor(_gd, cbs, template, _program.PipelineLayout);
+ }
+ }
- if (doUpdate)
+ private void ClearAndBindUniformBufferPd(CommandBufferScoped cbs)
+ {
+ var bindingSegments = _program.BindingSegments[PipelineBase.UniformSetIndex];
+
+ long updatedBindings = 0;
+ DescriptorSetTemplateWriter writer = _templateUpdater.Begin(32 * Unsafe.SizeOf<DescriptorBufferInfo>());
+
+ foreach (ResourceBindingSegment segment in bindingSegments)
+ {
+ int binding = segment.Binding;
+ int count = segment.Count;
+
+ for (int i = 0; i < count; i++)
{
- ReadOnlySpan<DescriptorBufferInfo> uniformBuffers = _uniformBuffers;
- UpdateBuffers(cbs, pbp, binding, uniformBuffers.Slice(binding, count), DescriptorType.UniformBuffer);
+ int index = binding + i;
+ updatedBindings |= 1L << index;
+
+ var bufferInfo = new DescriptorBufferInfo();
+ writer.Push(MemoryMarshal.CreateReadOnlySpan(ref bufferInfo, 1));
}
}
+
+ if (updatedBindings > 0)
+ {
+ DescriptorSetTemplate template = _program.GetPushDescriptorTemplate(updatedBindings);
+ _templateUpdater.CommitPushDescriptor(_gd, cbs, template, _program.PipelineLayout);
+ }
}
private void Initialize(CommandBufferScoped cbs, int setIndex, DescriptorSetCollection dsc)
@@ -724,6 +798,7 @@ namespace Ryujinx.Graphics.Vulkan
_uniformSet.Clear();
_storageSet.Clear();
+ AdvancePdSequence();
}
private static void SwapBuffer(BufferRef[] list, Auto<DisposableBuffer> from, Auto<DisposableBuffer> to)