123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- using System;
- using System.Runtime.InteropServices;
- using System.Threading.Tasks;
- using Avalonia;
- using Avalonia.Platform;
- using Avalonia.Rendering;
- using Avalonia.Rendering.Composition;
- using Avalonia.Vulkan;
- using Silk.NET.Vulkan;
- namespace GpuInterop.VulkanDemo;
- class VulkanSwapchain : SwapchainBase<VulkanSwapchainImage>
- {
- private readonly VulkanContext _vk;
- public VulkanSwapchain(VulkanContext vk, ICompositionGpuInterop interop, CompositionDrawingSurface target) : base(interop, target)
- {
- _vk = vk;
- }
- protected override VulkanSwapchainImage CreateImage(PixelSize size)
- {
- return new VulkanSwapchainImage(_vk, size, Interop, Target);
- }
- public IDisposable BeginDraw(PixelSize size, out VulkanImage image)
- {
- _vk.Pool.FreeUsedCommandBuffers();
- var rv = BeginDrawCore(size, out var swapchainImage);
- image = swapchainImage.Image;
- return rv;
- }
- }
- class VulkanSwapchainImage : ISwapchainImage
- {
- private readonly VulkanContext _vk;
- private readonly ICompositionGpuInterop _interop;
- private readonly CompositionDrawingSurface _target;
- private readonly VulkanImage _image;
- private readonly VulkanSemaphorePair? _semaphorePair;
- private readonly VulkanTimelineSemaphore? _timelineSemaphore;
- private ulong _timelineCounter;
- private ICompositionImportedGpuSemaphore? _availableSemaphore, _renderCompletedSemaphore, _importedTimelineSemaphore;
- private ICompositionImportedGpuImage? _importedImage;
- private Task? _lastPresent;
- public VulkanImage Image => _image;
- private bool _initial = true;
- public VulkanSwapchainImage(VulkanContext vk, PixelSize size, ICompositionGpuInterop interop, CompositionDrawingSurface target)
- {
- _vk = vk;
- _interop = interop;
- _target = target;
- Size = size;
- var format = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? Format.B8G8R8A8Unorm : Format.R8G8B8A8Unorm;
- _image = new VulkanImage(vk, (uint)format, size, true, interop.SupportedImageHandleTypes);
- if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
- _timelineSemaphore = new(vk);
- else
- _semaphorePair = new VulkanSemaphorePair(vk, true);
- }
- public async ValueTask DisposeAsync()
- {
- if (LastPresent != null)
- await LastPresent;
- if (_importedImage != null)
- await _importedImage.DisposeAsync();
-
- if (_availableSemaphore != null)
- await _availableSemaphore.DisposeAsync();
- if (_renderCompletedSemaphore != null)
- await _renderCompletedSemaphore.DisposeAsync();
- _semaphorePair?.Dispose();
- _timelineSemaphore?.Dispose();
- _image.Dispose();
- }
- public PixelSize Size { get; }
- public Task? LastPresent => _lastPresent;
- public void BeginDraw()
- {
- var buffer = _vk.Pool.CreateCommandBuffer();
- buffer.BeginRecording();
- _image.TransitionLayout(buffer.InternalHandle,
- ImageLayout.Undefined, AccessFlags.None,
- ImageLayout.ColorAttachmentOptimal, AccessFlags.ColorAttachmentReadBit);
- if(_image.IsDirectXBacked)
- buffer.Submit(null,null,null, null, new VulkanCommandBufferPool.VulkanCommandBuffer.KeyedMutexSubmitInfo
- {
- AcquireKey = 0,
- DeviceMemory = _image.DeviceMemory
- });
- else if (_timelineSemaphore != null)
- {
- unsafe
- {
- var wait = _timelineCounter;
- var submitInfo = new TimelineSemaphoreSubmitInfo
- {
- PWaitSemaphoreValues = &wait,
- WaitSemaphoreValueCount = 1,
- SType = StructureType.TimelineSemaphoreSubmitInfo
- };
- var waitSemaphores = new[] { _timelineSemaphore.Handle };
- buffer.Submit(waitSemaphores, pNext: (IntPtr)(&submitInfo));
- }
- }
- else if (_initial)
- {
- _initial = false;
- buffer.Submit();
- }
- else
- buffer.Submit(new[] { _semaphorePair.ImageAvailableSemaphore },
- new[]
- {
- PipelineStageFlags.AllGraphicsBit
- });
- }
-
-
- public void Present()
- {
- var buffer = _vk.Pool.CreateCommandBuffer();
- buffer.BeginRecording();
- _image.TransitionLayout(buffer.InternalHandle, ImageLayout.TransferSrcOptimal, AccessFlags.TransferWriteBit);
- if (_image.IsDirectXBacked)
- {
- buffer.Submit(null, null, null, null,
- new VulkanCommandBufferPool.VulkanCommandBuffer.KeyedMutexSubmitInfo
- {
- DeviceMemory = _image.DeviceMemory, ReleaseKey = 1
- });
- }
- else if (_timelineSemaphore != null)
- {
- unsafe
- {
- var signal = _timelineCounter + 1;
- var submitInfo = new TimelineSemaphoreSubmitInfo
- {
- PSignalSemaphoreValues = &signal,
- SignalSemaphoreValueCount = 1,
- SType = StructureType.TimelineSemaphoreSubmitInfo
- };
- var signalSemaphores = new[] { _timelineSemaphore.Handle };
- buffer.Submit(default, signalSemaphores: signalSemaphores, pNext: (IntPtr)(&submitInfo));
- }
- }
- else
- buffer.Submit(null, null, new[] { _semaphorePair.RenderFinishedSemaphore });
- if (_timelineSemaphore != null)
- {
- _importedTimelineSemaphore ??= _interop.ImportSemaphore(_timelineSemaphore.Export());
- }
- else if (!_image.IsDirectXBacked)
- {
- _availableSemaphore ??= _interop.ImportSemaphore(_semaphorePair.Export(false));
-
- _renderCompletedSemaphore ??= _interop.ImportSemaphore(_semaphorePair.Export(true));
- }
- _importedImage ??= _interop.ImportImage(_image.Export(),
- new PlatformGraphicsExternalImageProperties
- {
- Format = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? PlatformGraphicsExternalImageFormat.B8G8R8A8UNorm : PlatformGraphicsExternalImageFormat.R8G8B8A8UNorm,
- Width = Size.Width,
- Height = Size.Height,
- MemorySize = _image.MemorySize
- });
- if (_importedTimelineSemaphore != null)
- {
- _lastPresent = _target.UpdateWithTimelineSemaphoresAsync(_importedImage,
- _importedTimelineSemaphore, _timelineCounter + 1, _importedTimelineSemaphore, _timelineCounter + 2);
- _timelineCounter += 2;
- }
- else if (_image.IsDirectXBacked)
- _lastPresent = _target.UpdateWithKeyedMutexAsync(_importedImage, 1, 0);
- else
- _lastPresent = _target.UpdateWithSemaphoresAsync(_importedImage, _renderCompletedSemaphore!, _availableSemaphore!);
- }
- }
|