diff options
Diffstat (limited to 'Ryujinx.Ava/Ui/Controls/VulkanRendererControl.cs')
-rw-r--r-- | Ryujinx.Ava/Ui/Controls/VulkanRendererControl.cs | 107 |
1 files changed, 87 insertions, 20 deletions
diff --git a/Ryujinx.Ava/Ui/Controls/VulkanRendererControl.cs b/Ryujinx.Ava/Ui/Controls/VulkanRendererControl.cs index fdbd8df9..7b7dfaa1 100644 --- a/Ryujinx.Ava/Ui/Controls/VulkanRendererControl.cs +++ b/Ryujinx.Ava/Ui/Controls/VulkanRendererControl.cs @@ -1,4 +1,5 @@ using Avalonia; +using Avalonia.Media; using Avalonia.Platform; using Avalonia.Rendering.SceneGraph; using Avalonia.Skia; @@ -11,20 +12,23 @@ using Silk.NET.Vulkan; using SkiaSharp; using SPB.Windowing; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections.Concurrent; namespace Ryujinx.Ava.Ui.Controls { internal class VulkanRendererControl : RendererControl { + private const int MaxImagesInFlight = 3; + private VulkanPlatformInterface _platformInterface; + private ConcurrentQueue<PresentImageInfo> _imagesInFlight; + private PresentImageInfo _currentImage; public VulkanRendererControl(GraphicsDebugLevel graphicsDebugLevel) : base(graphicsDebugLevel) { _platformInterface = AvaloniaLocator.Current.GetService<VulkanPlatformInterface>(); + + _imagesInFlight = new ConcurrentQueue<PresentImageInfo>(); } public override void DestroyBackgroundContext() @@ -37,6 +41,40 @@ namespace Ryujinx.Ava.Ui.Controls return new VulkanDrawOperation(this); } + protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) + { + base.OnDetachedFromVisualTree(e); + + _imagesInFlight.Clear(); + + if (_platformInterface.MainSurface.Display != null) + { + _platformInterface.MainSurface.Display.Presented -= Window_Presented; + } + + _currentImage?.Put(); + _currentImage = null; + } + + protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) + { + base.OnAttachedToVisualTree(e); + + _platformInterface.MainSurface.Display.Presented += Window_Presented; + } + + private void Window_Presented(object sender, EventArgs e) + { + _platformInterface.MainSurface.Device.QueueWaitIdle(); + _currentImage?.Put(); + _currentImage = null; + } + + public override void Render(DrawingContext context) + { + base.Render(context); + } + protected override void CreateWindow() { } @@ -51,12 +89,29 @@ namespace Ryujinx.Ava.Ui.Controls internal override void Present(object image) { - Dispatcher.UIThread.InvokeAsync(() => + Image = image; + + _imagesInFlight.Enqueue((PresentImageInfo)image); + + if (_imagesInFlight.Count > MaxImagesInFlight) + { + _imagesInFlight.TryDequeue(out _); + } + + Dispatcher.UIThread.Post(InvalidateVisual); + } + + private PresentImageInfo GetImage() + { + lock (_imagesInFlight) { - Image = image; - }).Wait(); + if (!_imagesInFlight.TryDequeue(out _currentImage)) + { + _currentImage = (PresentImageInfo)Image; + } - QueueRender(); + return _currentImage; + } } private class VulkanDrawOperation : ICustomDrawOperation @@ -64,6 +119,7 @@ namespace Ryujinx.Ava.Ui.Controls public Rect Bounds { get; } private readonly VulkanRendererControl _control; + private bool _isDestroyed; public VulkanDrawOperation(VulkanRendererControl control) { @@ -73,7 +129,12 @@ namespace Ryujinx.Ava.Ui.Controls public void Dispose() { + if (_isDestroyed) + { + return; + } + _isDestroyed = true; } public bool Equals(ICustomDrawOperation other) @@ -86,30 +147,33 @@ namespace Ryujinx.Ava.Ui.Controls return Bounds.Contains(p); } - public void Render(IDrawingContextImpl context) + public unsafe void Render(IDrawingContextImpl context) { - if (_control.Image == null || _control.RenderSize.Width == 0 || _control.RenderSize.Height == 0) + if (_isDestroyed || _control.Image == null || _control.RenderSize.Width == 0 || _control.RenderSize.Height == 0 || + context is not ISkiaDrawingContextImpl skiaDrawingContextImpl) { return; } - var image = (PresentImageInfo)_control.Image; + var image = _control.GetImage(); - if (context is not ISkiaDrawingContextImpl skiaDrawingContextImpl) + if (!image.State.IsValid) { + _control._currentImage = null; + return; } - _control._platformInterface.Device.QueueWaitIdle(); - var gpu = AvaloniaLocator.Current.GetService<VulkanSkiaGpu>(); + image.Get(); + var imageInfo = new GRVkImageInfo() { CurrentQueueFamily = _control._platformInterface.PhysicalDevice.QueueFamilyIndex, Format = (uint)Format.R8G8B8A8Unorm, Image = image.Image.Handle, - ImageLayout = (uint)ImageLayout.ColorAttachmentOptimal, + ImageLayout = (uint)ImageLayout.TransferSrcOptimal, ImageTiling = (uint)ImageTiling.Optimal, ImageUsageFlags = (uint)(ImageUsageFlags.ImageUsageColorAttachmentBit | ImageUsageFlags.ImageUsageTransferSrcBit @@ -127,13 +191,15 @@ namespace Ryujinx.Ava.Ui.Controls }; using var backendTexture = new GRBackendRenderTarget( - (int)_control.RenderSize.Width, - (int)_control.RenderSize.Height, + (int)image.Extent.Width, + (int)image.Extent.Height, 1, imageInfo); + + var vulkan = AvaloniaLocator.Current.GetService<VulkanPlatformInterface>(); using var surface = SKSurface.Create( - gpu.GrContext, + skiaDrawingContextImpl.GrContext, backendTexture, GRSurfaceOrigin.TopLeft, SKColorType.Rgba8888); @@ -143,10 +209,11 @@ namespace Ryujinx.Ava.Ui.Controls return; } - var rect = new Rect(new Point(), _control.RenderSize); + var rect = new Rect(new Point(), new Size(image.Extent.Width, image.Extent.Height)); using var snapshot = surface.Snapshot(); - skiaDrawingContextImpl.SkCanvas.DrawImage(snapshot, rect.ToSKRect(), _control.Bounds.ToSKRect(), new SKPaint()); + skiaDrawingContextImpl.SkCanvas.DrawImage(snapshot, rect.ToSKRect(), _control.Bounds.ToSKRect(), + new SKPaint()); } } } |