Set update after bind flag if we exceed limits

This commit is contained in:
Gabriel A 2024-05-29 00:02:33 -03:00
parent 97fd5062d2
commit 306bc2c89d
4 changed files with 155 additions and 9 deletions

View file

@ -52,6 +52,12 @@ namespace Ryujinx.Graphics.Vulkan
public readonly uint VertexBufferAlignment;
public readonly uint SubTexelPrecisionBits;
public readonly ulong MinResourceAlignment;
public readonly uint MaxPerStageSampledImages;
public readonly uint MaxPerStageSamplers;
public readonly uint MaxPerStageStorageBuffers;
public readonly uint MaxPerStageStorageImages;
public readonly uint MaxPerStageUniformBuffers;
public readonly uint MaxPerStageResources;
public HardwareCapabilities(
bool supportsIndexTypeUint8,
@ -89,7 +95,13 @@ namespace Ryujinx.Graphics.Vulkan
PortabilitySubsetFlags portabilitySubset,
uint vertexBufferAlignment,
uint subTexelPrecisionBits,
ulong minResourceAlignment)
ulong minResourceAlignment,
uint maxPerStageSampledImages,
uint maxPerStageSamplers,
uint maxPerStageStorageBuffers,
uint maxPerStageStorageImages,
uint maxPerStageUniformBuffers,
uint maxPerStageResources)
{
SupportsIndexTypeUint8 = supportsIndexTypeUint8;
SupportsCustomBorderColor = supportsCustomBorderColor;
@ -127,6 +139,12 @@ namespace Ryujinx.Graphics.Vulkan
VertexBufferAlignment = vertexBufferAlignment;
SubTexelPrecisionBits = subTexelPrecisionBits;
MinResourceAlignment = minResourceAlignment;
MaxPerStageSampledImages = maxPerStageSampledImages;
MaxPerStageSamplers = maxPerStageSamplers;
MaxPerStageStorageBuffers = maxPerStageStorageBuffers;
MaxPerStageStorageImages = maxPerStageStorageImages;
MaxPerStageUniformBuffers = maxPerStageUniformBuffers;
MaxPerStageResources = maxPerStageResources;
}
}
}

View file

@ -16,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;
@ -98,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][];
@ -153,7 +158,7 @@ namespace Ryujinx.Graphics.Vulkan
_poolSizes[setIndex],
setIndex,
_consumedDescriptorsPerSet[setIndex],
false);
DescriptorSetLayoutsUpdateAfterBind[setIndex]);
list.Add(dsc);
isNew = true;
@ -196,7 +201,7 @@ namespace Ryujinx.Graphics.Vulkan
_poolSizes[setIndex],
setIndex,
_consumedDescriptorsPerSet[setIndex],
false);
DescriptorSetLayoutsUpdateAfterBind[setIndex]);
cacheIndex = list.Count;
list.Add(new ManualDescriptorSetEntry(dsc, cbs.CommandBufferIndex));

View file

@ -1,18 +1,117 @@
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(
private struct ResourceCounts
{
private Array5<int> _uniformBuffersCount;
private Array5<int> _storageBuffersCount;
private Array5<int> _texturesCount;
private Array5<int> _imagesCount;
private Array5<int> _samplersCount;
private Array5<int> _totalCount;
private void AddToStage(in ResourceDescriptor descriptor, int stageIndex)
{
switch (descriptor.Type)
{
case ResourceType.UniformBuffer:
_uniformBuffersCount[stageIndex] += descriptor.Count;
break;
case ResourceType.StorageBuffer:
_storageBuffersCount[stageIndex] += descriptor.Count;
break;
case ResourceType.Texture:
case ResourceType.TextureAndSampler:
case ResourceType.BufferTexture:
_texturesCount[stageIndex] += descriptor.Count;
break;
case ResourceType.Image:
case ResourceType.BufferImage:
_imagesCount[stageIndex] += descriptor.Count;
break;
case ResourceType.Sampler:
_samplersCount[stageIndex] += descriptor.Count;
break;
}
_totalCount[stageIndex] += descriptor.Count;
}
public void Add(in ResourceDescriptor descriptor)
{
if (descriptor.Stages.HasFlag(ResourceStages.Vertex) || descriptor.Stages.HasFlag(ResourceStages.Compute))
{
AddToStage(descriptor, 0);
}
if (descriptor.Stages.HasFlag(ResourceStages.TessellationControl))
{
AddToStage(descriptor, 1);
}
if (descriptor.Stages.HasFlag(ResourceStages.TessellationEvaluation))
{
AddToStage(descriptor, 2);
}
if (descriptor.Stages.HasFlag(ResourceStages.Geometry))
{
AddToStage(descriptor, 3);
}
if (descriptor.Stages.HasFlag(ResourceStages.Fragment))
{
AddToStage(descriptor, 4);
}
}
private static int Sum(ReadOnlySpan<int> values)
{
int sum = 0;
foreach (int value in values)
{
sum += value;
}
return sum;
}
public bool IsExceedingAnyMaxLimit(VulkanRenderer gd)
{
int maxUniformBuffers = Sum(_uniformBuffersCount.AsSpan());
int maxStorageBuffers = Sum(_storageBuffersCount.AsSpan());
int maxTextures = Sum(_texturesCount.AsSpan());
int maxImages = Sum(_imagesCount.AsSpan());
int maxSamplers = Sum(_samplersCount.AsSpan());
int maxTotal = Sum(_totalCount.AsSpan());
return (uint)maxUniformBuffers > gd.Capabilities.MaxPerStageUniformBuffers ||
(uint)maxStorageBuffers > gd.Capabilities.MaxPerStageStorageBuffers ||
(uint)maxTextures > gd.Capabilities.MaxPerStageSampledImages ||
(uint)maxImages > gd.Capabilities.MaxPerStageStorageImages ||
(uint)maxSamplers > gd.Capabilities.MaxPerStageSamplers ||
(uint)maxTotal > gd.Capabilities.MaxPerStageResources;
}
}
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;
@ -20,6 +119,7 @@ namespace Ryujinx.Graphics.Vulkan
{
ResourceDescriptorCollection rdc = setDescriptors[setIndex];
ResourceCounts counts = new();
ResourceStages activeStages = ResourceStages.None;
if (isMoltenVk)
@ -35,7 +135,6 @@ namespace Ryujinx.Graphics.Vulkan
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 +151,34 @@ namespace Ryujinx.Graphics.Vulkan
DescriptorCount = (uint)descriptor.Count,
StageFlags = stages.Convert(),
};
counts.Add(descriptor);
}
fixed (DescriptorSetLayoutBinding* pLayoutBindings = layoutBindings)
{
DescriptorSetLayoutCreateFlags flags = DescriptorSetLayoutCreateFlags.None;
if (usePushDescriptors && setIndex == 0)
{
flags = DescriptorSetLayoutCreateFlags.PushDescriptorBitKhr;
}
if (counts.IsExceedingAnyMaxLimit(gd))
{
// 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 +199,7 @@ namespace Ryujinx.Graphics.Vulkan
gd.Api.CreatePipelineLayout(device, &pipelineLayoutCreateInfo, null, out layout).ThrowOnError();
}
return (layouts, layout);
return new ResourceLayouts(layouts, updateAfterBindFlags, layout);
}
}
}

View file

@ -402,7 +402,13 @@ namespace Ryujinx.Graphics.Vulkan
portabilityFlags,
vertexBufferAlignment,
properties.Limits.SubTexelPrecisionBits,
minResourceAlignment);
minResourceAlignment,
properties.Limits.MaxPerStageDescriptorSampledImages,
properties.Limits.MaxPerStageDescriptorSamplers,
properties.Limits.MaxPerStageDescriptorStorageBuffers,
properties.Limits.MaxPerStageDescriptorStorageImages,
properties.Limits.MaxPerStageDescriptorUniformBuffers,
properties.Limits.MaxPerStageResources);
IsSharedMemory = MemoryAllocator.IsDeviceMemoryShared(_physicalDevice);