diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2024-05-26 13:30:19 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-05-26 13:30:19 -0300 |
| commit | 53d096e392d85106a41d8edad1dcda5cce7446a2 (patch) | |
| tree | 38fcf4a50e666c96c5c0ea133201f0b390bd14eb /src/Ryujinx.Graphics.Vulkan | |
| parent | 4cc00bb4b1b777734151cab5570d622fbfefa49f (diff) | |
Allow texture arrays to use separate descriptor sets on Vulkan (#6870)
* Report base and extra sets from the backend
* Pass texture set index everywhere
* Key textures using set and binding (rather than just binding)
* Start using extra sets for array textures
* Shader cache version bump
* Separate new commands, some PR feedback
* Introduce new manual descriptor set reservation method that prevents it from being used by something else while owned by an array
* Move bind extra sets logic to new method
* Should only use separate array is MaximumExtraSets is not zero
* Format whitespace
Diffstat (limited to 'src/Ryujinx.Graphics.Vulkan')
| -rw-r--r-- | src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs | 170 | ||||
| -rw-r--r-- | src/Ryujinx.Graphics.Vulkan/ImageArray.cs | 75 | ||||
| -rw-r--r-- | src/Ryujinx.Graphics.Vulkan/PipelineBase.cs | 16 | ||||
| -rw-r--r-- | src/Ryujinx.Graphics.Vulkan/PipelineLayoutCacheEntry.cs | 80 | ||||
| -rw-r--r-- | src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs | 10 | ||||
| -rw-r--r-- | src/Ryujinx.Graphics.Vulkan/TextureArray.cs | 76 | ||||
| -rw-r--r-- | src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs | 6 |
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, |
