2024-01-20 15:07:33 +01:00
|
|
|
using Ryujinx.Graphics.GAL;
|
|
|
|
using Silk.NET.Vulkan;
|
|
|
|
using System;
|
2024-02-17 01:41:30 +01:00
|
|
|
using System.Numerics;
|
2024-01-20 15:07:33 +01:00
|
|
|
using System.Runtime.CompilerServices;
|
|
|
|
|
|
|
|
namespace Ryujinx.Graphics.Vulkan
|
|
|
|
{
|
|
|
|
class DescriptorSetTemplate : IDisposable
|
|
|
|
{
|
2024-02-17 01:41:30 +01:00
|
|
|
/// <summary>
|
|
|
|
/// Renderdoc seems to crash when doing a templated uniform update with count > 1 on a push descriptor.
|
|
|
|
/// When this is true, consecutive buffers are always updated individually.
|
|
|
|
/// </summary>
|
|
|
|
private const bool RenderdocPushCountBug = true;
|
|
|
|
|
2024-01-20 15:07:33 +01:00
|
|
|
private readonly VulkanRenderer _gd;
|
|
|
|
private readonly Device _device;
|
|
|
|
|
|
|
|
public readonly DescriptorUpdateTemplate Template;
|
|
|
|
public readonly int Size;
|
|
|
|
|
2024-02-17 01:41:30 +01:00
|
|
|
public unsafe DescriptorSetTemplate(
|
|
|
|
VulkanRenderer gd,
|
|
|
|
Device device,
|
|
|
|
ResourceBindingSegment[] segments,
|
|
|
|
PipelineLayoutCacheEntry plce,
|
|
|
|
PipelineBindPoint pbp,
|
|
|
|
int setIndex)
|
2024-01-20 15:07:33 +01:00
|
|
|
{
|
|
|
|
_gd = gd;
|
|
|
|
_device = device;
|
|
|
|
|
|
|
|
// Create a template from the set usages. Assumes the descriptor set is updated in segment order then binding order.
|
|
|
|
|
|
|
|
DescriptorUpdateTemplateEntry* entries = stackalloc DescriptorUpdateTemplateEntry[segments.Length];
|
|
|
|
nuint structureOffset = 0;
|
|
|
|
|
|
|
|
for (int seg = 0; seg < segments.Length; seg++)
|
|
|
|
{
|
|
|
|
ResourceBindingSegment segment = segments[seg];
|
|
|
|
|
|
|
|
int binding = segment.Binding;
|
|
|
|
int count = segment.Count;
|
|
|
|
|
2024-04-22 20:05:55 +02:00
|
|
|
if (IsBufferType(segment.Type))
|
2024-01-20 15:07:33 +01:00
|
|
|
{
|
|
|
|
entries[seg] = new DescriptorUpdateTemplateEntry()
|
|
|
|
{
|
2024-04-22 20:05:55 +02:00
|
|
|
DescriptorType = segment.Type.Convert(),
|
2024-01-20 15:07:33 +01:00
|
|
|
DstBinding = (uint)binding,
|
|
|
|
DescriptorCount = (uint)count,
|
|
|
|
Offset = structureOffset,
|
|
|
|
Stride = (nuint)Unsafe.SizeOf<DescriptorBufferInfo>()
|
|
|
|
};
|
|
|
|
|
|
|
|
structureOffset += (nuint)(Unsafe.SizeOf<DescriptorBufferInfo>() * count);
|
|
|
|
}
|
2024-04-22 20:05:55 +02:00
|
|
|
else if (IsBufferTextureType(segment.Type))
|
2024-01-20 15:07:33 +01:00
|
|
|
{
|
|
|
|
entries[seg] = new DescriptorUpdateTemplateEntry()
|
|
|
|
{
|
2024-04-22 20:05:55 +02:00
|
|
|
DescriptorType = segment.Type.Convert(),
|
2024-01-20 15:07:33 +01:00
|
|
|
DstBinding = (uint)binding,
|
|
|
|
DescriptorCount = (uint)count,
|
|
|
|
Offset = structureOffset,
|
2024-04-22 20:05:55 +02:00
|
|
|
Stride = (nuint)Unsafe.SizeOf<BufferView>()
|
2024-01-20 15:07:33 +01:00
|
|
|
};
|
|
|
|
|
2024-04-22 20:05:55 +02:00
|
|
|
structureOffset += (nuint)(Unsafe.SizeOf<BufferView>() * count);
|
2024-01-20 15:07:33 +01:00
|
|
|
}
|
2024-04-22 20:05:55 +02:00
|
|
|
else
|
2024-01-20 15:07:33 +01:00
|
|
|
{
|
2024-04-22 20:05:55 +02:00
|
|
|
entries[seg] = new DescriptorUpdateTemplateEntry()
|
2024-01-20 15:07:33 +01:00
|
|
|
{
|
2024-04-22 20:05:55 +02:00
|
|
|
DescriptorType = segment.Type.Convert(),
|
|
|
|
DstBinding = (uint)binding,
|
|
|
|
DescriptorCount = (uint)count,
|
|
|
|
Offset = structureOffset,
|
|
|
|
Stride = (nuint)Unsafe.SizeOf<DescriptorImageInfo>()
|
|
|
|
};
|
|
|
|
|
|
|
|
structureOffset += (nuint)(Unsafe.SizeOf<DescriptorImageInfo>() * count);
|
2024-01-20 15:07:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Size = (int)structureOffset;
|
|
|
|
|
|
|
|
var info = new DescriptorUpdateTemplateCreateInfo()
|
|
|
|
{
|
|
|
|
SType = StructureType.DescriptorUpdateTemplateCreateInfo,
|
|
|
|
DescriptorUpdateEntryCount = (uint)segments.Length,
|
|
|
|
PDescriptorUpdateEntries = entries,
|
|
|
|
|
|
|
|
TemplateType = DescriptorUpdateTemplateType.DescriptorSet,
|
|
|
|
DescriptorSetLayout = plce.DescriptorSetLayouts[setIndex],
|
|
|
|
PipelineBindPoint = pbp,
|
|
|
|
PipelineLayout = plce.PipelineLayout,
|
|
|
|
Set = (uint)setIndex,
|
|
|
|
};
|
|
|
|
|
|
|
|
DescriptorUpdateTemplate result;
|
|
|
|
gd.Api.CreateDescriptorUpdateTemplate(device, &info, null, &result).ThrowOnError();
|
|
|
|
|
|
|
|
Template = result;
|
|
|
|
}
|
|
|
|
|
2024-02-17 01:41:30 +01:00
|
|
|
public unsafe DescriptorSetTemplate(
|
|
|
|
VulkanRenderer gd,
|
|
|
|
Device device,
|
|
|
|
ResourceDescriptorCollection descriptors,
|
|
|
|
long updateMask,
|
|
|
|
PipelineLayoutCacheEntry plce,
|
|
|
|
PipelineBindPoint pbp,
|
|
|
|
int setIndex)
|
|
|
|
{
|
|
|
|
_gd = gd;
|
|
|
|
_device = device;
|
|
|
|
|
|
|
|
// Create a template from the set usages. Assumes the descriptor set is updated in segment order then binding order.
|
|
|
|
int segmentCount = BitOperations.PopCount((ulong)updateMask);
|
|
|
|
|
|
|
|
DescriptorUpdateTemplateEntry* entries = stackalloc DescriptorUpdateTemplateEntry[segmentCount];
|
|
|
|
int entry = 0;
|
|
|
|
nuint structureOffset = 0;
|
|
|
|
|
|
|
|
void AddBinding(int binding, int count)
|
|
|
|
{
|
|
|
|
entries[entry++] = new DescriptorUpdateTemplateEntry()
|
|
|
|
{
|
|
|
|
DescriptorType = DescriptorType.UniformBuffer,
|
|
|
|
DstBinding = (uint)binding,
|
|
|
|
DescriptorCount = (uint)count,
|
|
|
|
Offset = structureOffset,
|
|
|
|
Stride = (nuint)Unsafe.SizeOf<DescriptorBufferInfo>()
|
|
|
|
};
|
|
|
|
|
|
|
|
structureOffset += (nuint)(Unsafe.SizeOf<DescriptorBufferInfo>() * count);
|
|
|
|
}
|
|
|
|
|
|
|
|
int startBinding = 0;
|
|
|
|
int bindingCount = 0;
|
|
|
|
|
|
|
|
foreach (ResourceDescriptor descriptor in descriptors.Descriptors)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < descriptor.Count; i++)
|
|
|
|
{
|
|
|
|
int binding = descriptor.Binding + i;
|
|
|
|
|
|
|
|
if ((updateMask & (1L << binding)) != 0)
|
|
|
|
{
|
|
|
|
if (bindingCount > 0 && (RenderdocPushCountBug || startBinding + bindingCount != binding))
|
|
|
|
{
|
|
|
|
AddBinding(startBinding, bindingCount);
|
|
|
|
|
|
|
|
bindingCount = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bindingCount == 0)
|
|
|
|
{
|
|
|
|
startBinding = binding;
|
|
|
|
}
|
|
|
|
|
|
|
|
bindingCount++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bindingCount > 0)
|
|
|
|
{
|
|
|
|
AddBinding(startBinding, bindingCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
Size = (int)structureOffset;
|
|
|
|
|
|
|
|
var info = new DescriptorUpdateTemplateCreateInfo()
|
|
|
|
{
|
|
|
|
SType = StructureType.DescriptorUpdateTemplateCreateInfo,
|
|
|
|
DescriptorUpdateEntryCount = (uint)entry,
|
|
|
|
PDescriptorUpdateEntries = entries,
|
|
|
|
|
|
|
|
TemplateType = DescriptorUpdateTemplateType.PushDescriptorsKhr,
|
|
|
|
DescriptorSetLayout = plce.DescriptorSetLayouts[setIndex],
|
|
|
|
PipelineBindPoint = pbp,
|
|
|
|
PipelineLayout = plce.PipelineLayout,
|
|
|
|
Set = (uint)setIndex,
|
|
|
|
};
|
|
|
|
|
|
|
|
DescriptorUpdateTemplate result;
|
|
|
|
gd.Api.CreateDescriptorUpdateTemplate(device, &info, null, &result).ThrowOnError();
|
|
|
|
|
|
|
|
Template = result;
|
|
|
|
}
|
|
|
|
|
2024-04-22 20:05:55 +02:00
|
|
|
private static bool IsBufferType(ResourceType type)
|
|
|
|
{
|
|
|
|
return type == ResourceType.UniformBuffer || type == ResourceType.StorageBuffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static bool IsBufferTextureType(ResourceType type)
|
|
|
|
{
|
|
|
|
return type == ResourceType.BufferTexture || type == ResourceType.BufferImage;
|
|
|
|
}
|
|
|
|
|
2024-01-20 15:07:33 +01:00
|
|
|
public unsafe void Dispose()
|
|
|
|
{
|
|
|
|
_gd.Api.DestroyDescriptorUpdateTemplate(_device, Template, null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|