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
This commit is contained in:
parent
4cc00bb4b1
commit
53d096e392
47 changed files with 996 additions and 262 deletions
|
@ -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)
|
||||
{
|
||||
_textureArrayRefs[binding].Array.Bound = false;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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.IncrementBindCount();
|
||||
textureArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags());
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
_imageArrayRefs[binding].Array.Bound = false;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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.IncrementBindCount();
|
||||
imageArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags());
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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++)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue