| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383 |
- using Ryujinx.Graphics.GAL;
- using Silk.NET.Vulkan;
- using System;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Diagnostics;
- using System.Runtime.InteropServices;
- namespace Ryujinx.Graphics.Vulkan
- {
- class PipelineLayoutCacheEntry
- {
- private const int MaxPoolSizesPerSet = 8;
- private readonly VulkanRenderer _gd;
- private readonly Device _device;
- public DescriptorSetLayout[] DescriptorSetLayouts { get; }
- public bool[] DescriptorSetLayoutsUpdateAfterBind { get; }
- public PipelineLayout PipelineLayout { get; }
- private readonly int[] _consumedDescriptorsPerSet;
- private readonly DescriptorPoolSize[][] _poolSizes;
- private readonly DescriptorSetManager _descriptorSetManager;
- private readonly List<Auto<DescriptorSetCollection>>[][] _dsCache;
- private List<Auto<DescriptorSetCollection>>[] _currentDsCache;
- private readonly int[] _dsCacheCursor;
- private int _dsLastCbIndex;
- private int _dsLastSubmissionCount;
- private struct ManualDescriptorSetEntry
- {
- public Auto<DescriptorSetCollection> DescriptorSet;
- public uint CbRefMask;
- public bool InUse;
- public ManualDescriptorSetEntry(Auto<DescriptorSetCollection> descriptorSet, int cbIndex)
- {
- DescriptorSet = descriptorSet;
- CbRefMask = 1u << cbIndex;
- InUse = true;
- }
- }
- private readonly struct PendingManualDsConsumption
- {
- public FenceHolder Fence { get; }
- public int CommandBufferIndex { get; }
- public int SetIndex { get; }
- public int CacheIndex { get; }
- public PendingManualDsConsumption(FenceHolder fence, int commandBufferIndex, int setIndex, int cacheIndex)
- {
- Fence = fence;
- CommandBufferIndex = commandBufferIndex;
- SetIndex = setIndex;
- CacheIndex = cacheIndex;
- fence.Get();
- }
- }
- private readonly List<ManualDescriptorSetEntry>[] _manualDsCache;
- private readonly Queue<PendingManualDsConsumption> _pendingManualDsConsumptions;
- private readonly Queue<int>[] _freeManualDsCacheEntries;
- private readonly Dictionary<long, DescriptorSetTemplate> _pdTemplates;
- private readonly ResourceDescriptorCollection _pdDescriptors;
- private long _lastPdUsage;
- private DescriptorSetTemplate _lastPdTemplate;
- private PipelineLayoutCacheEntry(VulkanRenderer gd, Device device, int setsCount)
- {
- _gd = gd;
- _device = device;
- _dsCache = new List<Auto<DescriptorSetCollection>>[CommandBufferPool.MaxCommandBuffers][];
- for (int i = 0; i < CommandBufferPool.MaxCommandBuffers; i++)
- {
- _dsCache[i] = new List<Auto<DescriptorSetCollection>>[setsCount];
- for (int j = 0; j < _dsCache[i].Length; j++)
- {
- _dsCache[i][j] = new List<Auto<DescriptorSetCollection>>();
- }
- }
- _dsCacheCursor = new int[setsCount];
- _manualDsCache = new List<ManualDescriptorSetEntry>[setsCount];
- _pendingManualDsConsumptions = new Queue<PendingManualDsConsumption>();
- _freeManualDsCacheEntries = new Queue<int>[setsCount];
- }
- public PipelineLayoutCacheEntry(
- VulkanRenderer gd,
- Device device,
- ReadOnlyCollection<ResourceDescriptorCollection> setDescriptors,
- bool usePushDescriptors) : this(gd, device, setDescriptors.Count)
- {
- ResourceLayouts layouts = PipelineLayoutFactory.Create(gd, device, setDescriptors, usePushDescriptors);
- DescriptorSetLayouts = layouts.DescriptorSetLayouts;
- DescriptorSetLayoutsUpdateAfterBind = layouts.DescriptorSetLayoutsUpdateAfterBind;
- PipelineLayout = layouts.PipelineLayout;
- _consumedDescriptorsPerSet = new int[setDescriptors.Count];
- _poolSizes = new DescriptorPoolSize[setDescriptors.Count][];
- Span<DescriptorPoolSize> poolSizes = stackalloc DescriptorPoolSize[MaxPoolSizesPerSet];
- for (int setIndex = 0; setIndex < setDescriptors.Count; setIndex++)
- {
- int count = 0;
- foreach (var descriptor in setDescriptors[setIndex].Descriptors)
- {
- count += descriptor.Count;
- }
- _consumedDescriptorsPerSet[setIndex] = count;
- _poolSizes[setIndex] = GetDescriptorPoolSizes(poolSizes, setDescriptors[setIndex], DescriptorSetManager.MaxSets).ToArray();
- }
- if (usePushDescriptors)
- {
- _pdDescriptors = setDescriptors[0];
- _pdTemplates = new();
- }
- _descriptorSetManager = new DescriptorSetManager(_device, setDescriptors.Count);
- }
- public void UpdateCommandBufferIndex(int commandBufferIndex)
- {
- int submissionCount = _gd.CommandBufferPool.GetSubmissionCount(commandBufferIndex);
- if (_dsLastCbIndex != commandBufferIndex || _dsLastSubmissionCount != submissionCount)
- {
- _dsLastCbIndex = commandBufferIndex;
- _dsLastSubmissionCount = submissionCount;
- Array.Clear(_dsCacheCursor);
- }
- _currentDsCache = _dsCache[commandBufferIndex];
- }
- public Auto<DescriptorSetCollection> GetNewDescriptorSetCollection(int setIndex, out bool isNew)
- {
- var list = _currentDsCache[setIndex];
- int index = _dsCacheCursor[setIndex]++;
- if (index == list.Count)
- {
- var dsc = _descriptorSetManager.AllocateDescriptorSet(
- _gd.Api,
- DescriptorSetLayouts[setIndex],
- _poolSizes[setIndex],
- setIndex,
- _consumedDescriptorsPerSet[setIndex],
- DescriptorSetLayoutsUpdateAfterBind[setIndex]);
- list.Add(dsc);
- isNew = true;
- return dsc;
- }
- isNew = false;
- return list[index];
- }
- public Auto<DescriptorSetCollection> GetNewManualDescriptorSetCollection(CommandBufferScoped cbs, int setIndex, out int cacheIndex)
- {
- FreeCompletedManualDescriptorSets();
- var list = _manualDsCache[setIndex] ??= new();
- var span = CollectionsMarshal.AsSpan(list);
- Queue<int> freeQueue = _freeManualDsCacheEntries[setIndex];
- // Do we have at least one freed descriptor set? If so, just use that.
- if (freeQueue != null && freeQueue.TryDequeue(out int freeIndex))
- {
- ref ManualDescriptorSetEntry entry = ref span[freeIndex];
- Debug.Assert(!entry.InUse && entry.CbRefMask == 0);
- entry.InUse = true;
- entry.CbRefMask = 1u << cbs.CommandBufferIndex;
- cacheIndex = freeIndex;
- _pendingManualDsConsumptions.Enqueue(new PendingManualDsConsumption(cbs.GetFence(), cbs.CommandBufferIndex, setIndex, freeIndex));
- return entry.DescriptorSet;
- }
- // Otherwise create a new descriptor set, and add to our pending queue for command buffer consumption tracking.
- var dsc = _descriptorSetManager.AllocateDescriptorSet(
- _gd.Api,
- DescriptorSetLayouts[setIndex],
- _poolSizes[setIndex],
- setIndex,
- _consumedDescriptorsPerSet[setIndex],
- DescriptorSetLayoutsUpdateAfterBind[setIndex]);
- cacheIndex = list.Count;
- list.Add(new ManualDescriptorSetEntry(dsc, cbs.CommandBufferIndex));
- _pendingManualDsConsumptions.Enqueue(new PendingManualDsConsumption(cbs.GetFence(), cbs.CommandBufferIndex, setIndex, cacheIndex));
- return dsc;
- }
- public void UpdateManualDescriptorSetCollectionOwnership(CommandBufferScoped cbs, int setIndex, int cacheIndex)
- {
- FreeCompletedManualDescriptorSets();
- var list = _manualDsCache[setIndex];
- var span = CollectionsMarshal.AsSpan(list);
- ref var entry = ref span[cacheIndex];
- uint cbMask = 1u << cbs.CommandBufferIndex;
- if ((entry.CbRefMask & cbMask) == 0)
- {
- entry.CbRefMask |= cbMask;
- _pendingManualDsConsumptions.Enqueue(new PendingManualDsConsumption(cbs.GetFence(), cbs.CommandBufferIndex, setIndex, cacheIndex));
- }
- }
- private void FreeCompletedManualDescriptorSets()
- {
- FenceHolder signalledFence = null;
- while (_pendingManualDsConsumptions.TryPeek(out var pds) && (pds.Fence == signalledFence || pds.Fence.IsSignaled()))
- {
- signalledFence = pds.Fence; // Already checked - don't need to do it again.
- var dequeued = _pendingManualDsConsumptions.Dequeue();
- Debug.Assert(dequeued.Fence == pds.Fence);
- pds.Fence.Put();
- var span = CollectionsMarshal.AsSpan(_manualDsCache[dequeued.SetIndex]);
- ref var entry = ref span[dequeued.CacheIndex];
- entry.CbRefMask &= ~(1u << dequeued.CommandBufferIndex);
- if (!entry.InUse && entry.CbRefMask == 0)
- {
- // If not in use by any array, and not bound to any command buffer, the descriptor set can be re-used immediately.
- (_freeManualDsCacheEntries[dequeued.SetIndex] ??= new()).Enqueue(dequeued.CacheIndex);
- }
- }
- }
- public void ReleaseManualDescriptorSetCollection(int setIndex, int cacheIndex)
- {
- var list = _manualDsCache[setIndex];
- var span = CollectionsMarshal.AsSpan(list);
- span[cacheIndex].InUse = false;
- if (span[cacheIndex].CbRefMask == 0)
- {
- // This is no longer in use by any array, so if not bound to any command buffer, the descriptor set can be re-used immediately.
- (_freeManualDsCacheEntries[setIndex] ??= new()).Enqueue(cacheIndex);
- }
- }
- private static Span<DescriptorPoolSize> GetDescriptorPoolSizes(Span<DescriptorPoolSize> output, ResourceDescriptorCollection setDescriptor, uint multiplier)
- {
- int count = 0;
- for (int index = 0; index < setDescriptor.Descriptors.Count; index++)
- {
- ResourceDescriptor descriptor = setDescriptor.Descriptors[index];
- DescriptorType descriptorType = descriptor.Type.Convert();
- bool found = false;
- for (int poolSizeIndex = 0; poolSizeIndex < count; poolSizeIndex++)
- {
- if (output[poolSizeIndex].Type == descriptorType)
- {
- output[poolSizeIndex].DescriptorCount += (uint)descriptor.Count * multiplier;
- found = true;
- break;
- }
- }
- if (!found)
- {
- output[count++] = new DescriptorPoolSize()
- {
- Type = descriptorType,
- DescriptorCount = (uint)descriptor.Count,
- };
- }
- }
- return output[..count];
- }
- public DescriptorSetTemplate GetPushDescriptorTemplate(PipelineBindPoint pbp, long updateMask)
- {
- if (_lastPdUsage == updateMask && _lastPdTemplate != null)
- {
- // Most likely result is that it asks to update the same buffers.
- return _lastPdTemplate;
- }
- if (!_pdTemplates.TryGetValue(updateMask, out DescriptorSetTemplate template))
- {
- template = new DescriptorSetTemplate(_gd, _device, _pdDescriptors, updateMask, this, pbp, 0);
- _pdTemplates.Add(updateMask, template);
- }
- _lastPdUsage = updateMask;
- _lastPdTemplate = template;
- return template;
- }
- protected virtual unsafe void Dispose(bool disposing)
- {
- if (disposing)
- {
- if (_pdTemplates != null)
- {
- foreach (DescriptorSetTemplate template in _pdTemplates.Values)
- {
- template.Dispose();
- }
- }
- for (int i = 0; i < _dsCache.Length; i++)
- {
- for (int j = 0; j < _dsCache[i].Length; j++)
- {
- for (int k = 0; k < _dsCache[i][j].Count; k++)
- {
- _dsCache[i][j][k].Dispose();
- }
- _dsCache[i][j].Clear();
- }
- }
- 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++)
- {
- _gd.Api.DestroyDescriptorSetLayout(_device, DescriptorSetLayouts[i], null);
- }
- while (_pendingManualDsConsumptions.TryDequeue(out var pds))
- {
- pds.Fence.Put();
- }
- _descriptorSetManager.Dispose();
- }
- }
- public void Dispose()
- {
- Dispose(true);
- }
- }
- }
|