aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Ava/Ui/Controls/VulkanRendererControl.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Ava/Ui/Controls/VulkanRendererControl.cs')
-rw-r--r--Ryujinx.Ava/Ui/Controls/VulkanRendererControl.cs107
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());
}
}
}