Vulkan separate descriptor set fixes (#6895)
* Ensure descriptor sets are only re-used when all command buffers using it have completed * Fix some SPIR-V capabilities * Set update after bind flag if we exceed limits * Simpler fix for Intel * Format whitespace * Make struct readonly * Add barriers for extra set arrays too
This commit is contained in:
parent
d7c6474729
commit
c0f2491eae
24 changed files with 365 additions and 113 deletions
|
@ -291,8 +291,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
}
|
||||
else
|
||||
{
|
||||
PipelineStageFlags stageFlags = _textureArrayRefs[segment.Binding].Stage.ConvertToPipelineStageFlags();
|
||||
_textureArrayRefs[segment.Binding].Array?.QueueWriteToReadBarriers(cbs, stageFlags);
|
||||
ref var arrayRef = ref _textureArrayRefs[segment.Binding];
|
||||
PipelineStageFlags stageFlags = arrayRef.Stage.ConvertToPipelineStageFlags();
|
||||
arrayRef.Array?.QueueWriteToReadBarriers(cbs, stageFlags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -311,8 +312,40 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
}
|
||||
else
|
||||
{
|
||||
PipelineStageFlags stageFlags = _imageArrayRefs[segment.Binding].Stage.ConvertToPipelineStageFlags();
|
||||
_imageArrayRefs[segment.Binding].Array?.QueueWriteToReadBarriers(cbs, stageFlags);
|
||||
ref var arrayRef = ref _imageArrayRefs[segment.Binding];
|
||||
PipelineStageFlags stageFlags = arrayRef.Stage.ConvertToPipelineStageFlags();
|
||||
arrayRef.Array?.QueueWriteToReadBarriers(cbs, stageFlags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (segment.Type == ResourceType.Texture ||
|
||||
segment.Type == ResourceType.Sampler ||
|
||||
segment.Type == ResourceType.TextureAndSampler ||
|
||||
segment.Type == ResourceType.BufferTexture)
|
||||
{
|
||||
ref var arrayRef = ref _textureArrayExtraRefs[setIndex - PipelineBase.DescriptorSetLayouts];
|
||||
PipelineStageFlags stageFlags = arrayRef.Stage.ConvertToPipelineStageFlags();
|
||||
arrayRef.Array?.QueueWriteToReadBarriers(cbs, stageFlags);
|
||||
}
|
||||
else if (segment.Type == ResourceType.Image || segment.Type == ResourceType.BufferImage)
|
||||
{
|
||||
ref var arrayRef = ref _imageArrayExtraRefs[setIndex - PipelineBase.DescriptorSetLayouts];
|
||||
PipelineStageFlags stageFlags = arrayRef.Stage.ConvertToPipelineStageFlags();
|
||||
arrayRef.Array?.QueueWriteToReadBarriers(cbs, stageFlags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,10 @@ using Ryujinx.Graphics.GAL;
|
|||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
class ImageArray : IImageArray
|
||||
class ImageArray : ResourceArray, IImageArray
|
||||
{
|
||||
private readonly VulkanRenderer _gd;
|
||||
|
||||
|
@ -25,19 +24,11 @@ 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;
|
||||
|
||||
private int _bindCount;
|
||||
|
||||
public ImageArray(VulkanRenderer gd, int size, bool isBuffer)
|
||||
{
|
||||
_gd = gd;
|
||||
|
@ -104,12 +95,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
{
|
||||
_cachedCommandBufferIndex = -1;
|
||||
_storages = null;
|
||||
_cachedDescriptorSets = null;
|
||||
|
||||
if (_bindCount != 0)
|
||||
{
|
||||
_gd.PipelineInternal.ForceImageDirty();
|
||||
}
|
||||
SetDirty(_gd);
|
||||
}
|
||||
|
||||
public void QueueWriteToReadBarriers(CommandBufferScoped cbs, PipelineStageFlags stageFlags)
|
||||
|
@ -195,7 +181,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
int setIndex,
|
||||
TextureView dummyTexture)
|
||||
{
|
||||
if (_cachedDescriptorSets != null)
|
||||
if (TryGetCachedDescriptorSets(cbs, program, setIndex, out DescriptorSet[] sets))
|
||||
{
|
||||
// We still need to ensure the current command buffer holds a reference to all used textures.
|
||||
|
||||
|
@ -208,12 +194,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
GetBufferViews(cbs);
|
||||
}
|
||||
|
||||
return _cachedDescriptorSets;
|
||||
return sets;
|
||||
}
|
||||
|
||||
_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);
|
||||
|
@ -227,24 +210,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ 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
|
||||
|
@ -15,6 +16,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
private readonly Device _device;
|
||||
|
||||
public DescriptorSetLayout[] DescriptorSetLayouts { get; }
|
||||
public bool[] DescriptorSetLayoutsUpdateAfterBind { get; }
|
||||
public PipelineLayout PipelineLayout { get; }
|
||||
|
||||
private readonly int[] _consumedDescriptorsPerSet;
|
||||
|
@ -31,20 +33,37 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
private struct ManualDescriptorSetEntry
|
||||
{
|
||||
public Auto<DescriptorSetCollection> DescriptorSet;
|
||||
public int CbIndex;
|
||||
public int CbSubmissionCount;
|
||||
public uint CbRefMask;
|
||||
public bool InUse;
|
||||
|
||||
public ManualDescriptorSetEntry(Auto<DescriptorSetCollection> descriptorSet, int cbIndex, int cbSubmissionCount, bool inUse)
|
||||
public ManualDescriptorSetEntry(Auto<DescriptorSetCollection> descriptorSet, int cbIndex)
|
||||
{
|
||||
DescriptorSet = descriptorSet;
|
||||
CbIndex = cbIndex;
|
||||
CbSubmissionCount = cbSubmissionCount;
|
||||
InUse = inUse;
|
||||
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;
|
||||
|
@ -70,6 +89,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
_dsCacheCursor = new int[setsCount];
|
||||
_manualDsCache = new List<ManualDescriptorSetEntry>[setsCount];
|
||||
_pendingManualDsConsumptions = new Queue<PendingManualDsConsumption>();
|
||||
_freeManualDsCacheEntries = new Queue<int>[setsCount];
|
||||
}
|
||||
|
||||
public PipelineLayoutCacheEntry(
|
||||
|
@ -78,7 +99,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
ReadOnlyCollection<ResourceDescriptorCollection> setDescriptors,
|
||||
bool usePushDescriptors) : this(gd, device, setDescriptors.Count)
|
||||
{
|
||||
(DescriptorSetLayouts, PipelineLayout) = PipelineLayoutFactory.Create(gd, device, setDescriptors, usePushDescriptors);
|
||||
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][];
|
||||
|
@ -133,7 +158,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
_poolSizes[setIndex],
|
||||
setIndex,
|
||||
_consumedDescriptorsPerSet[setIndex],
|
||||
false);
|
||||
DescriptorSetLayoutsUpdateAfterBind[setIndex]);
|
||||
|
||||
list.Add(dsc);
|
||||
isNew = true;
|
||||
|
@ -144,49 +169,99 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
return list[index];
|
||||
}
|
||||
|
||||
public Auto<DescriptorSetCollection> GetNewManualDescriptorSetCollection(int commandBufferIndex, int setIndex, out int cacheIndex)
|
||||
public Auto<DescriptorSetCollection> GetNewManualDescriptorSetCollection(CommandBufferScoped cbs, int setIndex, out int cacheIndex)
|
||||
{
|
||||
int submissionCount = _gd.CommandBufferPool.GetSubmissionCount(commandBufferIndex);
|
||||
FreeCompletedManualDescriptorSets();
|
||||
|
||||
var list = _manualDsCache[setIndex] ??= new();
|
||||
var span = CollectionsMarshal.AsSpan(list);
|
||||
|
||||
for (int index = 0; index < span.Length; index++)
|
||||
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[index];
|
||||
ref ManualDescriptorSetEntry entry = ref span[freeIndex];
|
||||
|
||||
if (!entry.InUse && (entry.CbIndex != commandBufferIndex || entry.CbSubmissionCount != submissionCount))
|
||||
{
|
||||
entry.InUse = true;
|
||||
entry.CbIndex = commandBufferIndex;
|
||||
entry.CbSubmissionCount = submissionCount;
|
||||
Debug.Assert(!entry.InUse && entry.CbRefMask == 0);
|
||||
|
||||
cacheIndex = index;
|
||||
entry.InUse = true;
|
||||
entry.CbRefMask = 1u << cbs.CommandBufferIndex;
|
||||
cacheIndex = freeIndex;
|
||||
|
||||
return entry.DescriptorSet;
|
||||
}
|
||||
_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],
|
||||
false);
|
||||
DescriptorSetLayoutsUpdateAfterBind[setIndex]);
|
||||
|
||||
cacheIndex = list.Count;
|
||||
list.Add(new ManualDescriptorSetEntry(dsc, commandBufferIndex, submissionCount, inUse: true));
|
||||
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)
|
||||
|
@ -291,6 +366,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
_gd.Api.DestroyDescriptorSetLayout(_device, DescriptorSetLayouts[i], null);
|
||||
}
|
||||
|
||||
while (_pendingManualDsConsumptions.TryDequeue(out var pds))
|
||||
{
|
||||
pds.Fence.Put();
|
||||
}
|
||||
|
||||
_descriptorSetManager.Dispose();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,23 @@
|
|||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
record struct ResourceLayouts(DescriptorSetLayout[] DescriptorSetLayouts, bool[] DescriptorSetLayoutsUpdateAfterBind, PipelineLayout PipelineLayout);
|
||||
|
||||
static class PipelineLayoutFactory
|
||||
{
|
||||
public static unsafe (DescriptorSetLayout[], PipelineLayout) Create(
|
||||
public static unsafe ResourceLayouts Create(
|
||||
VulkanRenderer gd,
|
||||
Device device,
|
||||
ReadOnlyCollection<ResourceDescriptorCollection> setDescriptors,
|
||||
bool usePushDescriptors)
|
||||
{
|
||||
DescriptorSetLayout[] layouts = new DescriptorSetLayout[setDescriptors.Count];
|
||||
bool[] updateAfterBindFlags = new bool[setDescriptors.Count];
|
||||
|
||||
bool isMoltenVk = gd.IsMoltenVk;
|
||||
|
||||
|
@ -32,10 +37,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
DescriptorSetLayoutBinding[] layoutBindings = new DescriptorSetLayoutBinding[rdc.Descriptors.Count];
|
||||
|
||||
bool hasArray = false;
|
||||
|
||||
for (int descIndex = 0; descIndex < rdc.Descriptors.Count; descIndex++)
|
||||
{
|
||||
ResourceDescriptor descriptor = rdc.Descriptors[descIndex];
|
||||
|
||||
ResourceStages stages = descriptor.Stages;
|
||||
|
||||
if (descriptor.Type == ResourceType.StorageBuffer && isMoltenVk)
|
||||
|
@ -52,16 +58,37 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
DescriptorCount = (uint)descriptor.Count,
|
||||
StageFlags = stages.Convert(),
|
||||
};
|
||||
|
||||
if (descriptor.Count > 1)
|
||||
{
|
||||
hasArray = true;
|
||||
}
|
||||
}
|
||||
|
||||
fixed (DescriptorSetLayoutBinding* pLayoutBindings = layoutBindings)
|
||||
{
|
||||
DescriptorSetLayoutCreateFlags flags = DescriptorSetLayoutCreateFlags.None;
|
||||
|
||||
if (usePushDescriptors && setIndex == 0)
|
||||
{
|
||||
flags = DescriptorSetLayoutCreateFlags.PushDescriptorBitKhr;
|
||||
}
|
||||
|
||||
if (gd.Vendor == Vendor.Intel && hasArray)
|
||||
{
|
||||
// Some vendors (like Intel) have low per-stage limits.
|
||||
// We must set the flag if we exceed those limits.
|
||||
flags |= DescriptorSetLayoutCreateFlags.UpdateAfterBindPoolBit;
|
||||
|
||||
updateAfterBindFlags[setIndex] = true;
|
||||
}
|
||||
|
||||
var descriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo
|
||||
{
|
||||
SType = StructureType.DescriptorSetLayoutCreateInfo,
|
||||
PBindings = pLayoutBindings,
|
||||
BindingCount = (uint)layoutBindings.Length,
|
||||
Flags = usePushDescriptors && setIndex == 0 ? DescriptorSetLayoutCreateFlags.PushDescriptorBitKhr : DescriptorSetLayoutCreateFlags.None,
|
||||
Flags = flags,
|
||||
};
|
||||
|
||||
gd.Api.CreateDescriptorSetLayout(device, descriptorSetLayoutCreateInfo, null, out layouts[setIndex]).ThrowOnError();
|
||||
|
@ -82,7 +109,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
gd.Api.CreatePipelineLayout(device, &pipelineLayoutCreateInfo, null, out layout).ThrowOnError();
|
||||
}
|
||||
|
||||
return (layouts, layout);
|
||||
return new ResourceLayouts(layouts, updateAfterBindFlags, layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
74
src/Ryujinx.Graphics.Vulkan/ResourceArray.cs
Normal file
74
src/Ryujinx.Graphics.Vulkan/ResourceArray.cs
Normal file
|
@ -0,0 +1,74 @@
|
|||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
class ResourceArray : IDisposable
|
||||
{
|
||||
private DescriptorSet[] _cachedDescriptorSets;
|
||||
|
||||
private ShaderCollection _cachedDscProgram;
|
||||
private int _cachedDscSetIndex;
|
||||
private int _cachedDscIndex;
|
||||
|
||||
private int _bindCount;
|
||||
|
||||
protected void SetDirty(VulkanRenderer gd)
|
||||
{
|
||||
ReleaseDescriptorSet();
|
||||
|
||||
if (_bindCount != 0)
|
||||
{
|
||||
gd.PipelineInternal.ForceTextureDirty();
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetCachedDescriptorSets(CommandBufferScoped cbs, ShaderCollection program, int setIndex, out DescriptorSet[] sets)
|
||||
{
|
||||
if (_cachedDescriptorSets != null)
|
||||
{
|
||||
_cachedDscProgram.UpdateManualDescriptorSetCollectionOwnership(cbs, _cachedDscSetIndex, _cachedDscIndex);
|
||||
|
||||
sets = _cachedDescriptorSets;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
var dsc = program.GetNewManualDescriptorSetCollection(cbs, setIndex, out _cachedDscIndex).Get(cbs);
|
||||
|
||||
sets = dsc.GetSets();
|
||||
|
||||
_cachedDescriptorSets = sets;
|
||||
_cachedDscProgram = program;
|
||||
_cachedDscSetIndex = setIndex;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void IncrementBindCount()
|
||||
{
|
||||
_bindCount++;
|
||||
}
|
||||
|
||||
public void DecrementBindCount()
|
||||
{
|
||||
int newBindCount = --_bindCount;
|
||||
Debug.Assert(newBindCount >= 0);
|
||||
}
|
||||
|
||||
private void ReleaseDescriptorSet()
|
||||
{
|
||||
if (_cachedDescriptorSets != null)
|
||||
{
|
||||
_cachedDscProgram.ReleaseManualDescriptorSetCollection(_cachedDscSetIndex, _cachedDscIndex);
|
||||
_cachedDescriptorSets = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ReleaseDescriptorSet();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -604,9 +604,14 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
return _plce.GetNewDescriptorSetCollection(setIndex, out isNew);
|
||||
}
|
||||
|
||||
public Auto<DescriptorSetCollection> GetNewManualDescriptorSetCollection(int commandBufferIndex, int setIndex, out int cacheIndex)
|
||||
public Auto<DescriptorSetCollection> GetNewManualDescriptorSetCollection(CommandBufferScoped cbs, int setIndex, out int cacheIndex)
|
||||
{
|
||||
return _plce.GetNewManualDescriptorSetCollection(commandBufferIndex, setIndex, out cacheIndex);
|
||||
return _plce.GetNewManualDescriptorSetCollection(cbs, setIndex, out cacheIndex);
|
||||
}
|
||||
|
||||
public void UpdateManualDescriptorSetCollectionOwnership(CommandBufferScoped cbs, int setIndex, int cacheIndex)
|
||||
{
|
||||
_plce.UpdateManualDescriptorSetCollectionOwnership(cbs, setIndex, cacheIndex);
|
||||
}
|
||||
|
||||
public void ReleaseManualDescriptorSetCollection(int setIndex, int cacheIndex)
|
||||
|
|
|
@ -2,11 +2,10 @@ using Ryujinx.Graphics.GAL;
|
|||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
class TextureArray : ITextureArray
|
||||
class TextureArray : ResourceArray, ITextureArray
|
||||
{
|
||||
private readonly VulkanRenderer _gd;
|
||||
|
||||
|
@ -25,19 +24,11 @@ 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;
|
||||
|
||||
private int _bindCount;
|
||||
|
||||
public TextureArray(VulkanRenderer gd, int size, bool isBuffer)
|
||||
{
|
||||
_gd = gd;
|
||||
|
@ -113,12 +104,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
{
|
||||
_cachedCommandBufferIndex = -1;
|
||||
_storages = null;
|
||||
_cachedDescriptorSets = null;
|
||||
|
||||
if (_bindCount != 0)
|
||||
{
|
||||
_gd.PipelineInternal.ForceTextureDirty();
|
||||
}
|
||||
SetDirty(_gd);
|
||||
}
|
||||
|
||||
public void QueueWriteToReadBarriers(CommandBufferScoped cbs, PipelineStageFlags stageFlags)
|
||||
|
@ -211,7 +197,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
TextureView dummyTexture,
|
||||
SamplerHolder dummySampler)
|
||||
{
|
||||
if (_cachedDescriptorSets != null)
|
||||
if (TryGetCachedDescriptorSets(cbs, program, setIndex, out DescriptorSet[] sets))
|
||||
{
|
||||
// We still need to ensure the current command buffer holds a reference to all used textures.
|
||||
|
||||
|
@ -224,12 +210,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
GetBufferViews(cbs);
|
||||
}
|
||||
|
||||
return _cachedDescriptorSets;
|
||||
return sets;
|
||||
}
|
||||
|
||||
_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);
|
||||
|
@ -243,24 +226,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue