diff options
Diffstat (limited to 'src/Ryujinx.Graphics.Vulkan/MemoryAllocator.cs')
-rw-r--r-- | src/Ryujinx.Graphics.Vulkan/MemoryAllocator.cs | 101 |
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(); + } + } + } +} |