aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Vulkan/BufferManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.Graphics.Vulkan/BufferManager.cs')
-rw-r--r--src/Ryujinx.Graphics.Vulkan/BufferManager.cs119
1 files changed, 116 insertions, 3 deletions
diff --git a/src/Ryujinx.Graphics.Vulkan/BufferManager.cs b/src/Ryujinx.Graphics.Vulkan/BufferManager.cs
index 20e00338..e9ac9884 100644
--- a/src/Ryujinx.Graphics.Vulkan/BufferManager.cs
+++ b/src/Ryujinx.Graphics.Vulkan/BufferManager.cs
@@ -96,25 +96,131 @@ namespace Ryujinx.Graphics.Vulkan
return Unsafe.As<ulong, BufferHandle>(ref handle64);
}
+ public unsafe BufferHandle CreateSparse(VulkanRenderer gd, ReadOnlySpan<BufferRange> storageBuffers)
+ {
+ var usage = DefaultBufferUsageFlags;
+
+ if (gd.Capabilities.SupportsIndirectParameters)
+ {
+ usage |= BufferUsageFlags.IndirectBufferBit;
+ }
+
+ ulong size = 0;
+
+ foreach (BufferRange range in storageBuffers)
+ {
+ size += (ulong)range.Size;
+ }
+
+ var bufferCreateInfo = new BufferCreateInfo()
+ {
+ SType = StructureType.BufferCreateInfo,
+ Size = size,
+ Usage = usage,
+ SharingMode = SharingMode.Exclusive,
+ Flags = BufferCreateFlags.SparseBindingBit | BufferCreateFlags.SparseAliasedBit
+ };
+
+ gd.Api.CreateBuffer(_device, in bufferCreateInfo, null, out var buffer).ThrowOnError();
+
+ var memoryBinds = new SparseMemoryBind[storageBuffers.Length];
+ var storageAllocations = new Auto<MemoryAllocation>[storageBuffers.Length];
+ int storageAllocationsCount = 0;
+
+ ulong dstOffset = 0;
+
+ for (int index = 0; index < storageBuffers.Length; index++)
+ {
+ BufferRange range = storageBuffers[index];
+
+ if (TryGetBuffer(range.Handle, out var existingHolder))
+ {
+ // Since this buffer now also owns the memory from the referenced buffer,
+ // we pin it to ensure the memory location will not change.
+ existingHolder.Pin();
+
+ (var memory, var offset) = existingHolder.GetDeviceMemoryAndOffset();
+
+ memoryBinds[index] = new SparseMemoryBind()
+ {
+ ResourceOffset = dstOffset,
+ Size = (ulong)range.Size,
+ Memory = memory,
+ MemoryOffset = offset + (ulong)range.Offset,
+ Flags = SparseMemoryBindFlags.None
+ };
+
+ storageAllocations[storageAllocationsCount++] = existingHolder.GetAllocation();
+ }
+ else
+ {
+ memoryBinds[index] = new SparseMemoryBind()
+ {
+ ResourceOffset = dstOffset,
+ Size = (ulong)range.Size,
+ Memory = default,
+ MemoryOffset = 0UL,
+ Flags = SparseMemoryBindFlags.None
+ };
+ }
+
+ dstOffset += (ulong)range.Size;
+ }
+
+ if (storageAllocations.Length != storageAllocationsCount)
+ {
+ Array.Resize(ref storageAllocations, storageAllocationsCount);
+ }
+
+ fixed (SparseMemoryBind* pMemoryBinds = memoryBinds)
+ {
+ SparseBufferMemoryBindInfo bufferBind = new SparseBufferMemoryBindInfo()
+ {
+ Buffer = buffer,
+ BindCount = (uint)memoryBinds.Length,
+ PBinds = pMemoryBinds
+ };
+
+ BindSparseInfo bindSparseInfo = new BindSparseInfo()
+ {
+ SType = StructureType.BindSparseInfo,
+ BufferBindCount = 1,
+ PBufferBinds = &bufferBind
+ };
+
+ gd.Api.QueueBindSparse(gd.Queue, 1, bindSparseInfo, default).ThrowOnError();
+ }
+
+ var holder = new BufferHolder(gd, _device, buffer, (int)size, storageAllocations);
+
+ BufferCount++;
+
+ ulong handle64 = (uint)_buffers.Add(holder);
+
+ return Unsafe.As<ulong, BufferHandle>(ref handle64);
+ }
+
public BufferHandle CreateWithHandle(
VulkanRenderer gd,
int size,
+ bool sparseCompatible = false,
BufferAllocationType baseType = BufferAllocationType.HostMapped,
BufferHandle storageHint = default,
bool forceMirrors = false)
{
- return CreateWithHandle(gd, size, out _, baseType, storageHint, forceMirrors);
+ return CreateWithHandle(gd, size, out _, sparseCompatible, baseType, storageHint, forceMirrors);
}
public BufferHandle CreateWithHandle(
VulkanRenderer gd,
int size,
out BufferHolder holder,
+ bool sparseCompatible = false,
BufferAllocationType baseType = BufferAllocationType.HostMapped,
BufferHandle storageHint = default,
bool forceMirrors = false)
{
- holder = Create(gd, size, baseType: baseType, storageHint: storageHint);
+ holder = Create(gd, size, forConditionalRendering: false, sparseCompatible, baseType, storageHint);
if (holder == null)
{
return BufferHandle.Null;
@@ -163,6 +269,7 @@ namespace Ryujinx.Graphics.Vulkan
int size,
BufferAllocationType type,
bool forConditionalRendering = false,
+ bool sparseCompatible = false,
BufferAllocationType fallbackType = BufferAllocationType.Auto)
{
var usage = DefaultBufferUsageFlags;
@@ -187,6 +294,11 @@ namespace Ryujinx.Graphics.Vulkan
gd.Api.CreateBuffer(_device, in bufferCreateInfo, null, out var buffer).ThrowOnError();
gd.Api.GetBufferMemoryRequirements(_device, buffer, out var requirements);
+ if (sparseCompatible)
+ {
+ requirements.Alignment = Math.Max(requirements.Alignment, Constants.SparseBufferAlignment);
+ }
+
MemoryAllocation allocation;
do
@@ -227,6 +339,7 @@ namespace Ryujinx.Graphics.Vulkan
VulkanRenderer gd,
int size,
bool forConditionalRendering = false,
+ bool sparseCompatible = false,
BufferAllocationType baseType = BufferAllocationType.HostMapped,
BufferHandle storageHint = default)
{
@@ -255,7 +368,7 @@ namespace Ryujinx.Graphics.Vulkan
}
(VkBuffer buffer, MemoryAllocation allocation, BufferAllocationType resultType) =
- CreateBacking(gd, size, type, forConditionalRendering);
+ CreateBacking(gd, size, type, forConditionalRendering, sparseCompatible);
if (buffer.Handle != 0)
{