VulkanSwapchain.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. using System;
  2. using System.Runtime.InteropServices;
  3. using System.Threading.Tasks;
  4. using Avalonia;
  5. using Avalonia.Platform;
  6. using Avalonia.Rendering;
  7. using Avalonia.Rendering.Composition;
  8. using Avalonia.Vulkan;
  9. using Silk.NET.Vulkan;
  10. namespace GpuInterop.VulkanDemo;
  11. class VulkanSwapchain : SwapchainBase<VulkanSwapchainImage>
  12. {
  13. private readonly VulkanContext _vk;
  14. public VulkanSwapchain(VulkanContext vk, ICompositionGpuInterop interop, CompositionDrawingSurface target) : base(interop, target)
  15. {
  16. _vk = vk;
  17. }
  18. protected override VulkanSwapchainImage CreateImage(PixelSize size)
  19. {
  20. return new VulkanSwapchainImage(_vk, size, Interop, Target);
  21. }
  22. public IDisposable BeginDraw(PixelSize size, out VulkanImage image)
  23. {
  24. _vk.Pool.FreeUsedCommandBuffers();
  25. var rv = BeginDrawCore(size, out var swapchainImage);
  26. image = swapchainImage.Image;
  27. return rv;
  28. }
  29. }
  30. class VulkanSwapchainImage : ISwapchainImage
  31. {
  32. private readonly VulkanContext _vk;
  33. private readonly ICompositionGpuInterop _interop;
  34. private readonly CompositionDrawingSurface _target;
  35. private readonly VulkanImage _image;
  36. private readonly VulkanSemaphorePair _semaphorePair;
  37. private ICompositionImportedGpuSemaphore? _availableSemaphore, _renderCompletedSemaphore;
  38. private ICompositionImportedGpuImage? _importedImage;
  39. private Task? _lastPresent;
  40. public VulkanImage Image => _image;
  41. private bool _initial = true;
  42. public VulkanSwapchainImage(VulkanContext vk, PixelSize size, ICompositionGpuInterop interop, CompositionDrawingSurface target)
  43. {
  44. _vk = vk;
  45. _interop = interop;
  46. _target = target;
  47. Size = size;
  48. _image = new VulkanImage(vk, (uint)Format.R8G8B8A8Unorm, size, true);
  49. _semaphorePair = new VulkanSemaphorePair(vk, true);
  50. }
  51. public async ValueTask DisposeAsync()
  52. {
  53. if (LastPresent != null)
  54. await LastPresent;
  55. if (_importedImage != null)
  56. await _importedImage.DisposeAsync();
  57. if (_availableSemaphore != null)
  58. await _availableSemaphore.DisposeAsync();
  59. if (_renderCompletedSemaphore != null)
  60. await _renderCompletedSemaphore.DisposeAsync();
  61. _semaphorePair.Dispose();
  62. _image.Dispose();
  63. }
  64. public PixelSize Size { get; }
  65. public Task? LastPresent => _lastPresent;
  66. public void BeginDraw()
  67. {
  68. var buffer = _vk.Pool.CreateCommandBuffer();
  69. buffer.BeginRecording();
  70. _image.TransitionLayout(buffer.InternalHandle,
  71. ImageLayout.Undefined, AccessFlags.None,
  72. ImageLayout.ColorAttachmentOptimal, AccessFlags.ColorAttachmentReadBit);
  73. if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
  74. buffer.Submit(null,null,null, null, new VulkanCommandBufferPool.VulkanCommandBuffer.KeyedMutexSubmitInfo
  75. {
  76. AcquireKey = 0,
  77. DeviceMemory = _image.DeviceMemory
  78. });
  79. else if (_initial)
  80. {
  81. _initial = false;
  82. buffer.Submit();
  83. }
  84. else
  85. buffer.Submit(new[] { _semaphorePair.ImageAvailableSemaphore },
  86. new[]
  87. {
  88. PipelineStageFlags.AllGraphicsBit
  89. });
  90. }
  91. public void Present()
  92. {
  93. var buffer = _vk.Pool.CreateCommandBuffer();
  94. buffer.BeginRecording();
  95. _image.TransitionLayout(buffer.InternalHandle, ImageLayout.TransferSrcOptimal, AccessFlags.TransferWriteBit);
  96. if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
  97. {
  98. buffer.Submit(null, null, null, null,
  99. new VulkanCommandBufferPool.VulkanCommandBuffer.KeyedMutexSubmitInfo
  100. {
  101. DeviceMemory = _image.DeviceMemory, ReleaseKey = 1
  102. });
  103. }
  104. else
  105. buffer.Submit(null, null, new[] { _semaphorePair.RenderFinishedSemaphore });
  106. if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
  107. {
  108. _availableSemaphore ??= _interop.ImportSemaphore(new PlatformHandle(
  109. new IntPtr(_semaphorePair.ExportFd(false)),
  110. KnownPlatformGraphicsExternalSemaphoreHandleTypes.VulkanOpaquePosixFileDescriptor));
  111. _renderCompletedSemaphore ??= _interop.ImportSemaphore(new PlatformHandle(
  112. new IntPtr(_semaphorePair.ExportFd(true)),
  113. KnownPlatformGraphicsExternalSemaphoreHandleTypes.VulkanOpaquePosixFileDescriptor));
  114. }
  115. _importedImage ??= _interop.ImportImage(_image.Export(),
  116. new PlatformGraphicsExternalImageProperties
  117. {
  118. Format = PlatformGraphicsExternalImageFormat.R8G8B8A8UNorm,
  119. Width = Size.Width,
  120. Height = Size.Height,
  121. MemorySize = _image.MemorySize
  122. });
  123. if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
  124. _lastPresent = _target.UpdateWithKeyedMutexAsync(_importedImage, 1, 0);
  125. else
  126. _lastPresent = _target.UpdateWithSemaphoresAsync(_importedImage, _renderCompletedSemaphore!, _availableSemaphore!);
  127. }
  128. }