Set update after bind flag if we exceed limits
This commit is contained in:
parent
97fd5062d2
commit
306bc2c89d
4 changed files with 155 additions and 9 deletions
|
@ -52,6 +52,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
public readonly uint VertexBufferAlignment;
|
public readonly uint VertexBufferAlignment;
|
||||||
public readonly uint SubTexelPrecisionBits;
|
public readonly uint SubTexelPrecisionBits;
|
||||||
public readonly ulong MinResourceAlignment;
|
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(
|
public HardwareCapabilities(
|
||||||
bool supportsIndexTypeUint8,
|
bool supportsIndexTypeUint8,
|
||||||
|
@ -89,7 +95,13 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
PortabilitySubsetFlags portabilitySubset,
|
PortabilitySubsetFlags portabilitySubset,
|
||||||
uint vertexBufferAlignment,
|
uint vertexBufferAlignment,
|
||||||
uint subTexelPrecisionBits,
|
uint subTexelPrecisionBits,
|
||||||
ulong minResourceAlignment)
|
ulong minResourceAlignment,
|
||||||
|
uint maxPerStageSampledImages,
|
||||||
|
uint maxPerStageSamplers,
|
||||||
|
uint maxPerStageStorageBuffers,
|
||||||
|
uint maxPerStageStorageImages,
|
||||||
|
uint maxPerStageUniformBuffers,
|
||||||
|
uint maxPerStageResources)
|
||||||
{
|
{
|
||||||
SupportsIndexTypeUint8 = supportsIndexTypeUint8;
|
SupportsIndexTypeUint8 = supportsIndexTypeUint8;
|
||||||
SupportsCustomBorderColor = supportsCustomBorderColor;
|
SupportsCustomBorderColor = supportsCustomBorderColor;
|
||||||
|
@ -127,6 +139,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
VertexBufferAlignment = vertexBufferAlignment;
|
VertexBufferAlignment = vertexBufferAlignment;
|
||||||
SubTexelPrecisionBits = subTexelPrecisionBits;
|
SubTexelPrecisionBits = subTexelPrecisionBits;
|
||||||
MinResourceAlignment = minResourceAlignment;
|
MinResourceAlignment = minResourceAlignment;
|
||||||
|
MaxPerStageSampledImages = maxPerStageSampledImages;
|
||||||
|
MaxPerStageSamplers = maxPerStageSamplers;
|
||||||
|
MaxPerStageStorageBuffers = maxPerStageStorageBuffers;
|
||||||
|
MaxPerStageStorageImages = maxPerStageStorageImages;
|
||||||
|
MaxPerStageUniformBuffers = maxPerStageUniformBuffers;
|
||||||
|
MaxPerStageResources = maxPerStageResources;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
private readonly Device _device;
|
private readonly Device _device;
|
||||||
|
|
||||||
public DescriptorSetLayout[] DescriptorSetLayouts { get; }
|
public DescriptorSetLayout[] DescriptorSetLayouts { get; }
|
||||||
|
public bool[] DescriptorSetLayoutsUpdateAfterBind { get; }
|
||||||
public PipelineLayout PipelineLayout { get; }
|
public PipelineLayout PipelineLayout { get; }
|
||||||
|
|
||||||
private readonly int[] _consumedDescriptorsPerSet;
|
private readonly int[] _consumedDescriptorsPerSet;
|
||||||
|
@ -98,7 +99,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
ReadOnlyCollection<ResourceDescriptorCollection> setDescriptors,
|
ReadOnlyCollection<ResourceDescriptorCollection> setDescriptors,
|
||||||
bool usePushDescriptors) : this(gd, device, setDescriptors.Count)
|
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];
|
_consumedDescriptorsPerSet = new int[setDescriptors.Count];
|
||||||
_poolSizes = new DescriptorPoolSize[setDescriptors.Count][];
|
_poolSizes = new DescriptorPoolSize[setDescriptors.Count][];
|
||||||
|
@ -153,7 +158,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_poolSizes[setIndex],
|
_poolSizes[setIndex],
|
||||||
setIndex,
|
setIndex,
|
||||||
_consumedDescriptorsPerSet[setIndex],
|
_consumedDescriptorsPerSet[setIndex],
|
||||||
false);
|
DescriptorSetLayoutsUpdateAfterBind[setIndex]);
|
||||||
|
|
||||||
list.Add(dsc);
|
list.Add(dsc);
|
||||||
isNew = true;
|
isNew = true;
|
||||||
|
@ -196,7 +201,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_poolSizes[setIndex],
|
_poolSizes[setIndex],
|
||||||
setIndex,
|
setIndex,
|
||||||
_consumedDescriptorsPerSet[setIndex],
|
_consumedDescriptorsPerSet[setIndex],
|
||||||
false);
|
DescriptorSetLayoutsUpdateAfterBind[setIndex]);
|
||||||
|
|
||||||
cacheIndex = list.Count;
|
cacheIndex = list.Count;
|
||||||
list.Add(new ManualDescriptorSetEntry(dsc, cbs.CommandBufferIndex));
|
list.Add(new ManualDescriptorSetEntry(dsc, cbs.CommandBufferIndex));
|
||||||
|
|
|
@ -1,18 +1,117 @@
|
||||||
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
|
using System;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
|
record struct ResourceLayouts(DescriptorSetLayout[] DescriptorSetLayouts, bool[] DescriptorSetLayoutsUpdateAfterBind, PipelineLayout PipelineLayout);
|
||||||
|
|
||||||
static class PipelineLayoutFactory
|
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,
|
VulkanRenderer gd,
|
||||||
Device device,
|
Device device,
|
||||||
ReadOnlyCollection<ResourceDescriptorCollection> setDescriptors,
|
ReadOnlyCollection<ResourceDescriptorCollection> setDescriptors,
|
||||||
bool usePushDescriptors)
|
bool usePushDescriptors)
|
||||||
{
|
{
|
||||||
DescriptorSetLayout[] layouts = new DescriptorSetLayout[setDescriptors.Count];
|
DescriptorSetLayout[] layouts = new DescriptorSetLayout[setDescriptors.Count];
|
||||||
|
bool[] updateAfterBindFlags = new bool[setDescriptors.Count];
|
||||||
|
|
||||||
bool isMoltenVk = gd.IsMoltenVk;
|
bool isMoltenVk = gd.IsMoltenVk;
|
||||||
|
|
||||||
|
@ -20,6 +119,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
ResourceDescriptorCollection rdc = setDescriptors[setIndex];
|
ResourceDescriptorCollection rdc = setDescriptors[setIndex];
|
||||||
|
|
||||||
|
ResourceCounts counts = new();
|
||||||
ResourceStages activeStages = ResourceStages.None;
|
ResourceStages activeStages = ResourceStages.None;
|
||||||
|
|
||||||
if (isMoltenVk)
|
if (isMoltenVk)
|
||||||
|
@ -35,7 +135,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
for (int descIndex = 0; descIndex < rdc.Descriptors.Count; descIndex++)
|
for (int descIndex = 0; descIndex < rdc.Descriptors.Count; descIndex++)
|
||||||
{
|
{
|
||||||
ResourceDescriptor descriptor = rdc.Descriptors[descIndex];
|
ResourceDescriptor descriptor = rdc.Descriptors[descIndex];
|
||||||
|
|
||||||
ResourceStages stages = descriptor.Stages;
|
ResourceStages stages = descriptor.Stages;
|
||||||
|
|
||||||
if (descriptor.Type == ResourceType.StorageBuffer && isMoltenVk)
|
if (descriptor.Type == ResourceType.StorageBuffer && isMoltenVk)
|
||||||
|
@ -52,16 +151,34 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
DescriptorCount = (uint)descriptor.Count,
|
DescriptorCount = (uint)descriptor.Count,
|
||||||
StageFlags = stages.Convert(),
|
StageFlags = stages.Convert(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
counts.Add(descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed (DescriptorSetLayoutBinding* pLayoutBindings = layoutBindings)
|
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
|
var descriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo
|
||||||
{
|
{
|
||||||
SType = StructureType.DescriptorSetLayoutCreateInfo,
|
SType = StructureType.DescriptorSetLayoutCreateInfo,
|
||||||
PBindings = pLayoutBindings,
|
PBindings = pLayoutBindings,
|
||||||
BindingCount = (uint)layoutBindings.Length,
|
BindingCount = (uint)layoutBindings.Length,
|
||||||
Flags = usePushDescriptors && setIndex == 0 ? DescriptorSetLayoutCreateFlags.PushDescriptorBitKhr : DescriptorSetLayoutCreateFlags.None,
|
Flags = flags,
|
||||||
};
|
};
|
||||||
|
|
||||||
gd.Api.CreateDescriptorSetLayout(device, descriptorSetLayoutCreateInfo, null, out layouts[setIndex]).ThrowOnError();
|
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();
|
gd.Api.CreatePipelineLayout(device, &pipelineLayoutCreateInfo, null, out layout).ThrowOnError();
|
||||||
}
|
}
|
||||||
|
|
||||||
return (layouts, layout);
|
return new ResourceLayouts(layouts, updateAfterBindFlags, layout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -402,7 +402,13 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
portabilityFlags,
|
portabilityFlags,
|
||||||
vertexBufferAlignment,
|
vertexBufferAlignment,
|
||||||
properties.Limits.SubTexelPrecisionBits,
|
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);
|
IsSharedMemory = MemoryAllocator.IsDeviceMemoryShared(_physicalDevice);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue