MemoryAllocator.cs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. using Silk.NET.Vulkan;
  2. using System;
  3. using System.Collections.Generic;
  4. namespace Ryujinx.Graphics.Vulkan
  5. {
  6. class MemoryAllocator : IDisposable
  7. {
  8. private ulong MaxDeviceMemoryUsageEstimate = 16UL * 1024 * 1024 * 1024;
  9. private readonly Vk _api;
  10. private readonly VulkanPhysicalDevice _physicalDevice;
  11. private readonly Device _device;
  12. private readonly List<MemoryAllocatorBlockList> _blockLists;
  13. private readonly int _blockAlignment;
  14. public MemoryAllocator(Vk api, VulkanPhysicalDevice physicalDevice, Device device)
  15. {
  16. _api = api;
  17. _physicalDevice = physicalDevice;
  18. _device = device;
  19. _blockLists = new List<MemoryAllocatorBlockList>();
  20. _blockAlignment = (int)Math.Min(int.MaxValue, MaxDeviceMemoryUsageEstimate / (ulong)_physicalDevice.PhysicalDeviceProperties.Limits.MaxMemoryAllocationCount);
  21. }
  22. public MemoryAllocation AllocateDeviceMemory(
  23. MemoryRequirements requirements,
  24. MemoryPropertyFlags flags = 0,
  25. bool isBuffer = false)
  26. {
  27. int memoryTypeIndex = FindSuitableMemoryTypeIndex(requirements.MemoryTypeBits, flags);
  28. if (memoryTypeIndex < 0)
  29. {
  30. return default;
  31. }
  32. bool map = flags.HasFlag(MemoryPropertyFlags.HostVisibleBit);
  33. return Allocate(memoryTypeIndex, requirements.Size, requirements.Alignment, map, isBuffer);
  34. }
  35. private MemoryAllocation Allocate(int memoryTypeIndex, ulong size, ulong alignment, bool map, bool isBuffer)
  36. {
  37. for (int i = 0; i < _blockLists.Count; i++)
  38. {
  39. var bl = _blockLists[i];
  40. if (bl.MemoryTypeIndex == memoryTypeIndex && bl.ForBuffer == isBuffer)
  41. {
  42. lock (bl)
  43. {
  44. return bl.Allocate(size, alignment, map);
  45. }
  46. }
  47. }
  48. var newBl = new MemoryAllocatorBlockList(_api, _device, memoryTypeIndex, _blockAlignment, isBuffer);
  49. _blockLists.Add(newBl);
  50. return newBl.Allocate(size, alignment, map);
  51. }
  52. private int FindSuitableMemoryTypeIndex(
  53. uint memoryTypeBits,
  54. MemoryPropertyFlags flags)
  55. {
  56. for (int i = 0; i < _physicalDevice.PhysicalDeviceMemoryProperties.MemoryTypeCount; i++)
  57. {
  58. var type = _physicalDevice.PhysicalDeviceMemoryProperties.MemoryTypes[i];
  59. if ((memoryTypeBits & (1 << i)) != 0)
  60. {
  61. if (type.PropertyFlags.HasFlag(flags))
  62. {
  63. return i;
  64. }
  65. }
  66. }
  67. return -1;
  68. }
  69. public static bool IsDeviceMemoryShared(VulkanPhysicalDevice physicalDevice)
  70. {
  71. for (int i = 0; i < physicalDevice.PhysicalDeviceMemoryProperties.MemoryHeapCount; i++)
  72. {
  73. if (!physicalDevice.PhysicalDeviceMemoryProperties.MemoryHeaps[i].Flags.HasFlag(MemoryHeapFlags.DeviceLocalBit))
  74. {
  75. return false;
  76. }
  77. }
  78. return true;
  79. }
  80. public void Dispose()
  81. {
  82. for (int i = 0; i < _blockLists.Count; i++)
  83. {
  84. _blockLists[i].Dispose();
  85. }
  86. }
  87. }
  88. }