diff options
Diffstat (limited to 'src/Ryujinx.Graphics.Vulkan/BufferManager.cs')
-rw-r--r-- | src/Ryujinx.Graphics.Vulkan/BufferManager.cs | 119 |
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) { |