diff options
Diffstat (limited to 'src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs')
-rw-r--r-- | src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs | 89 |
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) |