aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Vulkan/BufferManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.Vulkan/BufferManager.cs')
-rw-r--r--Ryujinx.Graphics.Vulkan/BufferManager.cs122
1 files changed, 93 insertions, 29 deletions
diff --git a/Ryujinx.Graphics.Vulkan/BufferManager.cs b/Ryujinx.Graphics.Vulkan/BufferManager.cs
index 49fdd75d..f8f41e5b 100644
--- a/Ryujinx.Graphics.Vulkan/BufferManager.cs
+++ b/Ryujinx.Graphics.Vulkan/BufferManager.cs
@@ -4,6 +4,7 @@ using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using VkFormat = Silk.NET.Vulkan.Format;
+using VkBuffer = Silk.NET.Vulkan.Buffer;
namespace Ryujinx.Graphics.Vulkan
{
@@ -16,17 +17,17 @@ namespace Ryujinx.Graphics.Vulkan
// Some drivers don't expose a "HostCached" memory type,
// so we need those alternative flags for the allocation to succeed there.
- private const MemoryPropertyFlags DefaultBufferMemoryAltFlags =
+ private const MemoryPropertyFlags DefaultBufferMemoryNoCacheFlags =
MemoryPropertyFlags.HostVisibleBit |
MemoryPropertyFlags.HostCoherentBit;
private const MemoryPropertyFlags DeviceLocalBufferMemoryFlags =
MemoryPropertyFlags.DeviceLocalBit;
- private const MemoryPropertyFlags FlushableDeviceLocalBufferMemoryFlags =
+ private const MemoryPropertyFlags DeviceLocalMappedBufferMemoryFlags =
+ MemoryPropertyFlags.DeviceLocalBit |
MemoryPropertyFlags.HostVisibleBit |
- MemoryPropertyFlags.HostCoherentBit |
- MemoryPropertyFlags.DeviceLocalBit;
+ MemoryPropertyFlags.HostCoherentBit;
private const BufferUsageFlags DefaultBufferUsageFlags =
BufferUsageFlags.TransferSrcBit |
@@ -54,14 +55,14 @@ namespace Ryujinx.Graphics.Vulkan
StagingBuffer = new StagingBuffer(gd, this);
}
- public BufferHandle CreateWithHandle(VulkanRenderer gd, int size, bool deviceLocal)
+ public BufferHandle CreateWithHandle(VulkanRenderer gd, int size, BufferAllocationType baseType = BufferAllocationType.HostMapped, BufferHandle storageHint = default)
{
- return CreateWithHandle(gd, size, deviceLocal, out _);
+ return CreateWithHandle(gd, size, out _, baseType, storageHint);
}
- public BufferHandle CreateWithHandle(VulkanRenderer gd, int size, bool deviceLocal, out BufferHolder holder)
+ public BufferHandle CreateWithHandle(VulkanRenderer gd, int size, out BufferHolder holder, BufferAllocationType baseType = BufferAllocationType.HostMapped, BufferHandle storageHint = default)
{
- holder = Create(gd, size, deviceLocal: deviceLocal);
+ holder = Create(gd, size, baseType: baseType, storageHint: storageHint);
if (holder == null)
{
return BufferHandle.Null;
@@ -74,7 +75,12 @@ namespace Ryujinx.Graphics.Vulkan
return Unsafe.As<ulong, BufferHandle>(ref handle64);
}
- public unsafe BufferHolder Create(VulkanRenderer gd, int size, bool forConditionalRendering = false, bool deviceLocal = false)
+ public unsafe (VkBuffer buffer, MemoryAllocation allocation, BufferAllocationType resultType) CreateBacking(
+ VulkanRenderer gd,
+ int size,
+ BufferAllocationType type,
+ bool forConditionalRendering = false,
+ BufferAllocationType fallbackType = BufferAllocationType.Auto)
{
var usage = DefaultBufferUsageFlags;
@@ -98,48 +104,106 @@ namespace Ryujinx.Graphics.Vulkan
gd.Api.CreateBuffer(_device, in bufferCreateInfo, null, out var buffer).ThrowOnError();
gd.Api.GetBufferMemoryRequirements(_device, buffer, out var requirements);
- MemoryPropertyFlags allocateFlags;
- MemoryPropertyFlags allocateFlagsAlt;
+ MemoryAllocation allocation;
- if (deviceLocal)
- {
- allocateFlags = DeviceLocalBufferMemoryFlags;
- allocateFlagsAlt = DeviceLocalBufferMemoryFlags;
- }
- else
+ do
{
- allocateFlags = DefaultBufferMemoryFlags;
- allocateFlagsAlt = DefaultBufferMemoryAltFlags;
+ var allocateFlags = type switch
+ {
+ BufferAllocationType.HostMappedNoCache => DefaultBufferMemoryNoCacheFlags,
+ BufferAllocationType.HostMapped => DefaultBufferMemoryFlags,
+ BufferAllocationType.DeviceLocal => DeviceLocalBufferMemoryFlags,
+ BufferAllocationType.DeviceLocalMapped => DeviceLocalMappedBufferMemoryFlags,
+ _ => DefaultBufferMemoryFlags
+ };
+
+ // If an allocation with this memory type fails, fall back to the previous one.
+ try
+ {
+ allocation = gd.MemoryAllocator.AllocateDeviceMemory(requirements, allocateFlags, true);
+ }
+ catch (VulkanException)
+ {
+ allocation = default;
+ }
}
-
- var allocation = gd.MemoryAllocator.AllocateDeviceMemory(requirements, allocateFlags, allocateFlagsAlt);
+ while (allocation.Memory.Handle == 0 && (--type != fallbackType));
if (allocation.Memory.Handle == 0UL)
{
gd.Api.DestroyBuffer(_device, buffer, null);
- return null;
+ return default;
}
gd.Api.BindBufferMemory(_device, buffer, allocation.Memory, allocation.Offset);
- return new BufferHolder(gd, _device, buffer, allocation, size);
+ return (buffer, allocation, type);
}
- public Auto<DisposableBufferView> CreateView(BufferHandle handle, VkFormat format, int offset, int size)
+ public unsafe BufferHolder Create(
+ VulkanRenderer gd,
+ int size,
+ bool forConditionalRendering = false,
+ BufferAllocationType baseType = BufferAllocationType.HostMapped,
+ BufferHandle storageHint = default)
+ {
+ BufferAllocationType type = baseType;
+ BufferHolder storageHintHolder = null;
+
+ if (baseType == BufferAllocationType.Auto)
+ {
+ if (gd.IsSharedMemory)
+ {
+ baseType = BufferAllocationType.HostMapped;
+ type = baseType;
+ }
+ else
+ {
+ type = size >= BufferHolder.DeviceLocalSizeThreshold ? BufferAllocationType.DeviceLocal : BufferAllocationType.HostMapped;
+ }
+
+ if (storageHint != BufferHandle.Null)
+ {
+ if (TryGetBuffer(storageHint, out storageHintHolder))
+ {
+ type = storageHintHolder.DesiredType;
+ }
+ }
+ }
+
+ (VkBuffer buffer, MemoryAllocation allocation, BufferAllocationType resultType) =
+ CreateBacking(gd, size, type, forConditionalRendering);
+
+ if (buffer.Handle != 0)
+ {
+ var holder = new BufferHolder(gd, _device, buffer, allocation, size, baseType, resultType);
+
+ if (storageHintHolder != null)
+ {
+ holder.InheritMetrics(storageHintHolder);
+ }
+
+ return holder;
+ }
+
+ return null;
+ }
+
+ public Auto<DisposableBufferView> CreateView(BufferHandle handle, VkFormat format, int offset, int size, Action invalidateView)
{
if (TryGetBuffer(handle, out var holder))
{
- return holder.CreateView(format, offset, size);
+ return holder.CreateView(format, offset, size, invalidateView);
}
return null;
}
- public Auto<DisposableBuffer> GetBuffer(CommandBuffer commandBuffer, BufferHandle handle, bool isWrite)
+ public Auto<DisposableBuffer> GetBuffer(CommandBuffer commandBuffer, BufferHandle handle, bool isWrite, bool isSSBO = false)
{
if (TryGetBuffer(handle, out var holder))
{
- return holder.GetBuffer(commandBuffer, isWrite);
+ return holder.GetBuffer(commandBuffer, isWrite, isSSBO);
}
return null;
@@ -332,14 +396,14 @@ namespace Ryujinx.Graphics.Vulkan
return null;
}
- public ReadOnlySpan<byte> GetData(BufferHandle handle, int offset, int size)
+ public PinnedSpan<byte> GetData(BufferHandle handle, int offset, int size)
{
if (TryGetBuffer(handle, out var holder))
{
return holder.GetData(offset, size);
}
- return ReadOnlySpan<byte>.Empty;
+ return new PinnedSpan<byte>();
}
public void SetData<T>(BufferHandle handle, int offset, ReadOnlySpan<T> data) where T : unmanaged