Use push descriptors for uniform buffer updates (disabled for now)

This commit is contained in:
gdk 2022-06-15 00:42:03 -03:00 committed by riperiperi
parent f2b1cfe10c
commit db4e7d28ea
8 changed files with 105 additions and 14 deletions

View file

@ -223,22 +223,29 @@ namespace Ryujinx.Graphics.Vulkan
if (_dirty.HasFlag(DirtyFlags.Uniform))
{
UpdateAndBind(cbs, PipelineBase.UniformSetIndex, DirtyFlags.Uniform, pbp);
if (_program.UsePushDescriptors)
{
UpdateAndBindUniformBufferPd(cbs, pbp);
}
else
{
UpdateAndBind(cbs, PipelineBase.UniformSetIndex, pbp);
}
}
if (_dirty.HasFlag(DirtyFlags.Storage))
{
UpdateAndBind(cbs, PipelineBase.StorageSetIndex, DirtyFlags.Storage, pbp);
UpdateAndBind(cbs, PipelineBase.StorageSetIndex, pbp);
}
if (_dirty.HasFlag(DirtyFlags.Texture))
{
UpdateAndBind(cbs, PipelineBase.TextureSetIndex, DirtyFlags.Texture, pbp);
UpdateAndBind(cbs, PipelineBase.TextureSetIndex, pbp);
}
if (_dirty.HasFlag(DirtyFlags.Image))
{
UpdateAndBind(cbs, PipelineBase.ImageSetIndex, DirtyFlags.Image, pbp);
UpdateAndBind(cbs, PipelineBase.ImageSetIndex, pbp);
}
_dirty = DirtyFlags.None;
@ -263,7 +270,7 @@ namespace Ryujinx.Graphics.Vulkan
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void UpdateAndBind(CommandBufferScoped cbs, int setIndex, DirtyFlags flag, PipelineBindPoint pbp)
private void UpdateAndBind(CommandBufferScoped cbs, int setIndex, PipelineBindPoint pbp)
{
var program = _program;
int stagesCount = program.Bindings[setIndex].Length;
@ -402,6 +409,77 @@ namespace Ryujinx.Graphics.Vulkan
_gd.Api.CmdBindDescriptorSets(cbs.CommandBuffer, pbp, _program.PipelineLayout, (uint)setIndex, 1, sets, 0, ReadOnlySpan<uint>.Empty);
}
private unsafe void UpdateBuffers(
CommandBufferScoped cbs,
PipelineBindPoint pbp,
int baseBinding,
ReadOnlySpan<DescriptorBufferInfo> bufferInfo,
DescriptorType type)
{
if (bufferInfo.Length == 0)
{
return;
}
fixed (DescriptorBufferInfo* pBufferInfo = bufferInfo)
{
var writeDescriptorSet = new WriteDescriptorSet
{
SType = StructureType.WriteDescriptorSet,
DstBinding = (uint)baseBinding,
DescriptorType = type,
DescriptorCount = (uint)bufferInfo.Length,
PBufferInfo = pBufferInfo
};
_gd.PushDescriptorApi.CmdPushDescriptorSet(cbs.CommandBuffer, pbp, _program.PipelineLayout, 0, 1, &writeDescriptorSet);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void UpdateAndBindUniformBufferPd(CommandBufferScoped cbs, PipelineBindPoint pbp)
{
var dummyBuffer = _dummyBuffer?.GetBuffer();
int stagesCount = _program.Bindings[PipelineBase.UniformSetIndex].Length;
Span<DescriptorBufferInfo> uniformBuffer = stackalloc DescriptorBufferInfo[1];
uniformBuffer[0] = new DescriptorBufferInfo()
{
Offset = 0,
Range = (ulong)SupportBuffer.RequiredSize,
Buffer = _gd.BufferManager.GetBuffer(cbs.CommandBuffer, _pipeline.SupportBufferUpdater.Handle, false).Get(cbs, 0, SupportBuffer.RequiredSize).Value
};
UpdateBuffers(cbs, pbp, 0, uniformBuffer, DescriptorType.UniformBuffer);
for (int stageIndex = 0; stageIndex < stagesCount; stageIndex++)
{
var stageBindings = _program.Bindings[PipelineBase.UniformSetIndex][stageIndex];
int bindingsCount = stageBindings.Length;
int count;
for (int bindingIndex = 0; bindingIndex < bindingsCount; bindingIndex += count)
{
int binding = stageBindings[bindingIndex];
count = 1;
while (bindingIndex + count < bindingsCount && stageBindings[bindingIndex + count] == binding + count)
{
count++;
}
for (int i = 0; i < count; i++)
{
UpdateBuffer(cbs, ref _uniformBuffers[binding + i], _uniformBufferRefs[binding + i], dummyBuffer);
}
ReadOnlySpan<DescriptorBufferInfo> uniformBuffers = _uniformBuffers;
UpdateBuffers(cbs, pbp, binding, uniformBuffers.Slice(binding, count), DescriptorType.UniformBuffer);
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Initialize(CommandBufferScoped cbs, int setIndex, DescriptorSetCollection dsc)
{

View file

@ -22,11 +22,11 @@ namespace Ryujinx.Graphics.Vulkan
return plce;
}
public PipelineLayoutCacheEntry GetOrCreate(VulkanGraphicsDevice gd, Device device, uint stages)
public PipelineLayoutCacheEntry GetOrCreate(VulkanGraphicsDevice gd, Device device, uint stages, bool usePd)
{
if (_plce[stages] == null)
{
_plce[stages] = new PipelineLayoutCacheEntry(gd, device, stages);
_plce[stages] = new PipelineLayoutCacheEntry(gd, device, stages, usePd);
}
return _plce[stages];

View file

@ -36,9 +36,9 @@ namespace Ryujinx.Graphics.Vulkan
_dsCacheCursor = new int[PipelineBase.DescriptorSetLayouts];
}
public PipelineLayoutCacheEntry(VulkanGraphicsDevice gd, Device device, uint stages) : this(gd, device)
public PipelineLayoutCacheEntry(VulkanGraphicsDevice gd, Device device, uint stages, bool usePd) : this(gd, device)
{
DescriptorSetLayouts = PipelineLayoutFactory.Create(gd, device, stages, out var pipelineLayout);
DescriptorSetLayouts = PipelineLayoutFactory.Create(gd, device, stages, usePd, out var pipelineLayout);
PipelineLayout = pipelineLayout;
}

View file

@ -12,7 +12,7 @@ namespace Ryujinx.Graphics.Vulkan
ShaderStageFlags.ShaderStageFragmentBit |
ShaderStageFlags.ShaderStageComputeBit;
public static unsafe DescriptorSetLayout[] Create(VulkanGraphicsDevice gd, Device device, uint stages, out PipelineLayout layout)
public static unsafe DescriptorSetLayout[] Create(VulkanGraphicsDevice gd, Device device, uint stages, bool usePd, out PipelineLayout layout)
{
int stagesCount = BitOperations.PopCount(stages);
@ -92,7 +92,8 @@ namespace Ryujinx.Graphics.Vulkan
{
SType = StructureType.DescriptorSetLayoutCreateInfo,
PBindings = uLayoutBindings,
BindingCount = (uint)uCount
BindingCount = (uint)uCount,
Flags = usePd ? DescriptorSetLayoutCreateFlags.DescriptorSetLayoutCreatePushDescriptorBitKhr : 0
};
var sDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()

View file

@ -18,6 +18,7 @@ namespace Ryujinx.Graphics.Vulkan
public PipelineLayout PipelineLayout => _plce.PipelineLayout;
public bool HasMinimalLayout { get; }
public bool UsePushDescriptors { get; }
public uint Stages { get; }
@ -89,11 +90,14 @@ namespace Ryujinx.Graphics.Vulkan
_shaders = internalShaders;
bool usePd = !isMinimal && VulkanConfiguration.UsePushDescriptors;
_plce = isMinimal
? gd.PipelineLayoutCache.Create(gd, device, shaders)
: gd.PipelineLayoutCache.GetOrCreate(gd, device, stages);
: gd.PipelineLayoutCache.GetOrCreate(gd, device, stages, usePd);
HasMinimalLayout = isMinimal;
UsePushDescriptors = usePd;
Stages = stages;

View file

@ -7,6 +7,7 @@
public const bool UseFastBufferUpdates = true;
public const bool UseGranularBufferTracking = true;
public const bool UseSlowSafeBlitOnAmd = true;
public const bool UsePushDescriptors = false;
public const bool ForceD24S8Unsupported = false;
}

View file

@ -31,6 +31,7 @@ namespace Ryujinx.Graphics.Vulkan
internal KhrSwapchain SwapchainApi { get; private set; }
internal ExtConditionalRendering ConditionalRenderingApi { get; private set; }
internal ExtExtendedDynamicState ExtendedDynamicStateApi { get; private set; }
internal KhrPushDescriptor PushDescriptorApi { get; private set; }
internal ExtTransformFeedback TransformFeedbackApi { get; private set; }
internal KhrDrawIndirectCount DrawIndirectCountApi { get; private set; }
internal ExtDebugReport DebugReportApi { get; private set; }
@ -137,6 +138,11 @@ namespace Ryujinx.Graphics.Vulkan
ExtendedDynamicStateApi = extendedDynamicStateApi;
}
if (Api.TryGetDeviceExtension(_instance, _device, out KhrPushDescriptor pushDescriptorApi))
{
PushDescriptorApi = pushDescriptorApi;
}
if (Api.TryGetDeviceExtension(_instance, _device, out ExtTransformFeedback transformFeedbackApi))
{
TransformFeedbackApi = transformFeedbackApi;

View file

@ -22,14 +22,15 @@ namespace Ryujinx.Graphics.Vulkan
ExtConditionalRendering.ExtensionName,
ExtExtendedDynamicState.ExtensionName,
KhrDrawIndirectCount.ExtensionName,
KhrPushDescriptor.ExtensionName,
"VK_EXT_custom_border_color",
"VK_EXT_descriptor_indexing", // Enabling this works around an issue with disposed buffer bindings on RADV.
"VK_EXT_fragment_shader_interlock",
"VK_EXT_index_type_uint8",
"VK_EXT_robustness2",
"VK_EXT_shader_subgroup_ballot",
"VK_EXT_subgroup_size_control",
"VK_NV_geometry_shader_passthrough",
"VK_EXT_descriptor_indexing" // Enabling this works around an issue with disposed buffer bindings on RADV.
"VK_NV_geometry_shader_passthrough"
};
public static string[] RequiredExtensions { get; } = new string[]