aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Vulkan/MemoryAllocator.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.Graphics.Vulkan/MemoryAllocator.cs')
-rw-r--r--src/Ryujinx.Graphics.Vulkan/MemoryAllocator.cs101
1 files changed, 101 insertions, 0 deletions
diff --git a/src/Ryujinx.Graphics.Vulkan/MemoryAllocator.cs b/src/Ryujinx.Graphics.Vulkan/MemoryAllocator.cs
new file mode 100644
index 00000000..3139e209
--- /dev/null
+++ b/src/Ryujinx.Graphics.Vulkan/MemoryAllocator.cs
@@ -0,0 +1,101 @@
+using Silk.NET.Vulkan;
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.Graphics.Vulkan
+{
+ class MemoryAllocator : IDisposable
+ {
+ private ulong MaxDeviceMemoryUsageEstimate = 16UL * 1024 * 1024 * 1024;
+
+ private readonly Vk _api;
+ private readonly VulkanPhysicalDevice _physicalDevice;
+ private readonly Device _device;
+ private readonly List<MemoryAllocatorBlockList> _blockLists;
+ private readonly int _blockAlignment;
+
+ public MemoryAllocator(Vk api, VulkanPhysicalDevice physicalDevice, Device device)
+ {
+ _api = api;
+ _physicalDevice = physicalDevice;
+ _device = device;
+ _blockLists = new List<MemoryAllocatorBlockList>();
+ _blockAlignment = (int)Math.Min(int.MaxValue, MaxDeviceMemoryUsageEstimate / (ulong)_physicalDevice.PhysicalDeviceProperties.Limits.MaxMemoryAllocationCount);
+ }
+
+ public MemoryAllocation AllocateDeviceMemory(
+ MemoryRequirements requirements,
+ MemoryPropertyFlags flags = 0,
+ bool isBuffer = false)
+ {
+ int memoryTypeIndex = FindSuitableMemoryTypeIndex(requirements.MemoryTypeBits, flags);
+ if (memoryTypeIndex < 0)
+ {
+ return default;
+ }
+
+ bool map = flags.HasFlag(MemoryPropertyFlags.HostVisibleBit);
+ return Allocate(memoryTypeIndex, requirements.Size, requirements.Alignment, map, isBuffer);
+ }
+
+ private MemoryAllocation Allocate(int memoryTypeIndex, ulong size, ulong alignment, bool map, bool isBuffer)
+ {
+ for (int i = 0; i < _blockLists.Count; i++)
+ {
+ var bl = _blockLists[i];
+ if (bl.MemoryTypeIndex == memoryTypeIndex && bl.ForBuffer == isBuffer)
+ {
+ lock (bl)
+ {
+ return bl.Allocate(size, alignment, map);
+ }
+ }
+ }
+
+ var newBl = new MemoryAllocatorBlockList(_api, _device, memoryTypeIndex, _blockAlignment, isBuffer);
+ _blockLists.Add(newBl);
+ return newBl.Allocate(size, alignment, map);
+ }
+
+ private int FindSuitableMemoryTypeIndex(
+ uint memoryTypeBits,
+ MemoryPropertyFlags flags)
+ {
+ for (int i = 0; i < _physicalDevice.PhysicalDeviceMemoryProperties.MemoryTypeCount; i++)
+ {
+ var type = _physicalDevice.PhysicalDeviceMemoryProperties.MemoryTypes[i];
+
+ if ((memoryTypeBits & (1 << i)) != 0)
+ {
+ if (type.PropertyFlags.HasFlag(flags))
+ {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+ }
+
+ public static bool IsDeviceMemoryShared(VulkanPhysicalDevice physicalDevice)
+ {
+ for (int i = 0; i < physicalDevice.PhysicalDeviceMemoryProperties.MemoryHeapCount; i++)
+ {
+ if (!physicalDevice.PhysicalDeviceMemoryProperties.MemoryHeaps[i].Flags.HasFlag(MemoryHeapFlags.DeviceLocalBit))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public void Dispose()
+ {
+ for (int i = 0; i < _blockLists.Count; i++)
+ {
+ _blockLists[i].Dispose();
+ }
+ }
+ }
+}