VulkanCommandBufferPool.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. using System;
  2. using System.Collections.Generic;
  3. using Silk.NET.Vulkan;
  4. namespace Ryujinx.Ava.Ui.Vulkan
  5. {
  6. internal class VulkanCommandBufferPool : IDisposable
  7. {
  8. private readonly VulkanDevice _device;
  9. private readonly CommandPool _commandPool;
  10. private readonly List<VulkanCommandBuffer> _usedCommandBuffers = new();
  11. public unsafe VulkanCommandBufferPool(VulkanDevice device, VulkanPhysicalDevice physicalDevice)
  12. {
  13. _device = device;
  14. var commandPoolCreateInfo = new CommandPoolCreateInfo
  15. {
  16. SType = StructureType.CommandPoolCreateInfo,
  17. Flags = CommandPoolCreateFlags.CommandPoolCreateResetCommandBufferBit,
  18. QueueFamilyIndex = physicalDevice.QueueFamilyIndex
  19. };
  20. device.Api.CreateCommandPool(_device.InternalHandle, commandPoolCreateInfo, null, out _commandPool)
  21. .ThrowOnError();
  22. }
  23. private CommandBuffer AllocateCommandBuffer()
  24. {
  25. var commandBufferAllocateInfo = new CommandBufferAllocateInfo
  26. {
  27. SType = StructureType.CommandBufferAllocateInfo,
  28. CommandPool = _commandPool,
  29. CommandBufferCount = 1,
  30. Level = CommandBufferLevel.Primary
  31. };
  32. _device.Api.AllocateCommandBuffers(_device.InternalHandle, commandBufferAllocateInfo, out var commandBuffer);
  33. return commandBuffer;
  34. }
  35. public VulkanCommandBuffer CreateCommandBuffer()
  36. {
  37. return new(_device, this);
  38. }
  39. public void FreeUsedCommandBuffers()
  40. {
  41. lock (_usedCommandBuffers)
  42. {
  43. foreach (var usedCommandBuffer in _usedCommandBuffers)
  44. {
  45. usedCommandBuffer.Dispose();
  46. }
  47. _usedCommandBuffers.Clear();
  48. }
  49. }
  50. private void DisposeCommandBuffer(VulkanCommandBuffer commandBuffer)
  51. {
  52. lock (_usedCommandBuffers)
  53. {
  54. _usedCommandBuffers.Add(commandBuffer);
  55. }
  56. }
  57. public void Dispose()
  58. {
  59. FreeUsedCommandBuffers();
  60. _device.Api.DestroyCommandPool(_device.InternalHandle, _commandPool, Span<AllocationCallbacks>.Empty);
  61. }
  62. public class VulkanCommandBuffer : IDisposable
  63. {
  64. private readonly VulkanCommandBufferPool _commandBufferPool;
  65. private readonly VulkanDevice _device;
  66. private readonly Fence _fence;
  67. private bool _hasEnded;
  68. private bool _hasStarted;
  69. public IntPtr Handle => InternalHandle.Handle;
  70. internal CommandBuffer InternalHandle { get; }
  71. internal unsafe VulkanCommandBuffer(VulkanDevice device, VulkanCommandBufferPool commandBufferPool)
  72. {
  73. _device = device;
  74. _commandBufferPool = commandBufferPool;
  75. InternalHandle = _commandBufferPool.AllocateCommandBuffer();
  76. var fenceCreateInfo = new FenceCreateInfo()
  77. {
  78. SType = StructureType.FenceCreateInfo,
  79. Flags = FenceCreateFlags.FenceCreateSignaledBit
  80. };
  81. device.Api.CreateFence(device.InternalHandle, fenceCreateInfo, null, out _fence);
  82. }
  83. public void BeginRecording()
  84. {
  85. if (!_hasStarted)
  86. {
  87. _hasStarted = true;
  88. var beginInfo = new CommandBufferBeginInfo
  89. {
  90. SType = StructureType.CommandBufferBeginInfo,
  91. Flags = CommandBufferUsageFlags.CommandBufferUsageOneTimeSubmitBit
  92. };
  93. _device.Api.BeginCommandBuffer(InternalHandle, beginInfo);
  94. }
  95. }
  96. public void EndRecording()
  97. {
  98. if (_hasStarted && !_hasEnded)
  99. {
  100. _hasEnded = true;
  101. _device.Api.EndCommandBuffer(InternalHandle);
  102. }
  103. }
  104. public void Submit()
  105. {
  106. Submit(null, null, null, _fence);
  107. }
  108. public unsafe void Submit(
  109. ReadOnlySpan<Semaphore> waitSemaphores,
  110. ReadOnlySpan<PipelineStageFlags> waitDstStageMask,
  111. ReadOnlySpan<Semaphore> signalSemaphores,
  112. Fence? fence = null)
  113. {
  114. EndRecording();
  115. if (!fence.HasValue)
  116. {
  117. fence = _fence;
  118. }
  119. fixed (Semaphore* pWaitSemaphores = waitSemaphores, pSignalSemaphores = signalSemaphores)
  120. {
  121. fixed (PipelineStageFlags* pWaitDstStageMask = waitDstStageMask)
  122. {
  123. var commandBuffer = InternalHandle;
  124. var submitInfo = new SubmitInfo
  125. {
  126. SType = StructureType.SubmitInfo,
  127. WaitSemaphoreCount = waitSemaphores != null ? (uint)waitSemaphores.Length : 0,
  128. PWaitSemaphores = pWaitSemaphores,
  129. PWaitDstStageMask = pWaitDstStageMask,
  130. CommandBufferCount = 1,
  131. PCommandBuffers = &commandBuffer,
  132. SignalSemaphoreCount = signalSemaphores != null ? (uint)signalSemaphores.Length : 0,
  133. PSignalSemaphores = pSignalSemaphores,
  134. };
  135. _device.Api.ResetFences(_device.InternalHandle, 1, fence.Value);
  136. _device.Submit(submitInfo, fence.Value);
  137. }
  138. }
  139. _commandBufferPool.DisposeCommandBuffer(this);
  140. }
  141. public void Dispose()
  142. {
  143. _device.Api.WaitForFences(_device.InternalHandle, 1, _fence, true, ulong.MaxValue);
  144. _device.Api.FreeCommandBuffers(_device.InternalHandle, _commandBufferPool._commandPool, 1, InternalHandle);
  145. _device.Api.DestroyFence(_device.InternalHandle, _fence, Span<AllocationCallbacks>.Empty);
  146. }
  147. }
  148. }
  149. }