aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Ava/Ui/Backend/Vulkan
diff options
context:
space:
mode:
authorEmmanuel Hansen <emmausssss@gmail.com>2022-08-16 16:32:37 +0000
committerGitHub <noreply@github.com>2022-08-16 16:32:37 +0000
commitc8f9292babd5aa6021ce1bd6a977130baebb7de3 (patch)
treee6e62d79d08726129485476078732f9b89f6ab5c /Ryujinx.Ava/Ui/Backend/Vulkan
parent0ec933a6152ebb7724da1e3a05a5ae1c2ea07b2f (diff)
Avalonia - Couple fixes and improvements to vulkan (#3483)
* drop split devices, rebase * add fallback to opengl if vulkan is not available * addressed review * ensure present image references are incremented and decremented when necessary * allow changing vsync for vulkan * fix screenshot on avalonia vulkan * save favorite when toggled * improve sync between popups * use separate devices for each new window * fix crash when closing window * addressed review * don't create the main window with immediate mode * change skia vk delegate to method * update vulkan throwonerror * addressed review
Diffstat (limited to 'Ryujinx.Ava/Ui/Backend/Vulkan')
-rw-r--r--Ryujinx.Ava/Ui/Backend/Vulkan/ResultExtensions.cs3
-rw-r--r--Ryujinx.Ava/Ui/Backend/Vulkan/Skia/VulkanRenderTarget.cs78
-rw-r--r--Ryujinx.Ava/Ui/Backend/Vulkan/Skia/VulkanSkiaGpu.cs67
-rw-r--r--Ryujinx.Ava/Ui/Backend/Vulkan/Surfaces/VulkanSurfaceRenderTarget.cs96
-rw-r--r--Ryujinx.Ava/Ui/Backend/Vulkan/VulkanCommandBufferPool.cs51
-rw-r--r--Ryujinx.Ava/Ui/Backend/Vulkan/VulkanDevice.cs10
-rw-r--r--Ryujinx.Ava/Ui/Backend/Vulkan/VulkanDisplay.cs47
-rw-r--r--Ryujinx.Ava/Ui/Backend/Vulkan/VulkanImage.cs22
-rw-r--r--Ryujinx.Ava/Ui/Backend/Vulkan/VulkanInstance.cs3
-rw-r--r--Ryujinx.Ava/Ui/Backend/Vulkan/VulkanOptions.cs5
-rw-r--r--Ryujinx.Ava/Ui/Backend/Vulkan/VulkanPlatformInterface.cs12
-rw-r--r--Ryujinx.Ava/Ui/Backend/Vulkan/VulkanSurfaceRenderingSession.cs9
12 files changed, 236 insertions, 167 deletions
diff --git a/Ryujinx.Ava/Ui/Backend/Vulkan/ResultExtensions.cs b/Ryujinx.Ava/Ui/Backend/Vulkan/ResultExtensions.cs
index b1326dbf..2a1cd229 100644
--- a/Ryujinx.Ava/Ui/Backend/Vulkan/ResultExtensions.cs
+++ b/Ryujinx.Ava/Ui/Backend/Vulkan/ResultExtensions.cs
@@ -7,7 +7,8 @@ namespace Ryujinx.Ava.Ui.Vulkan
{
public static void ThrowOnError(this Result result)
{
- if (result != Result.Success)
+ // Only negative result codes are errors.
+ if ((int)result < (int)Result.Success)
{
throw new Exception($"Unexpected API error \"{result}\".");
}
diff --git a/Ryujinx.Ava/Ui/Backend/Vulkan/Skia/VulkanRenderTarget.cs b/Ryujinx.Ava/Ui/Backend/Vulkan/Skia/VulkanRenderTarget.cs
index ba7ddc7a..70ec39c7 100644
--- a/Ryujinx.Ava/Ui/Backend/Vulkan/Skia/VulkanRenderTarget.cs
+++ b/Ryujinx.Ava/Ui/Backend/Vulkan/Skia/VulkanRenderTarget.cs
@@ -1,26 +1,90 @@
using System;
+using Avalonia;
using Avalonia.Skia;
using Ryujinx.Ava.Ui.Vulkan;
using Ryujinx.Ava.Ui.Vulkan.Surfaces;
+using Silk.NET.Vulkan;
using SkiaSharp;
namespace Ryujinx.Ava.Ui.Backend.Vulkan
{
internal class VulkanRenderTarget : ISkiaGpuRenderTarget
{
- public GRContext GrContext { get; set; }
+ public GRContext GrContext { get; private set; }
private readonly VulkanSurfaceRenderTarget _surface;
+ private readonly VulkanPlatformInterface _vulkanPlatformInterface;
private readonly IVulkanPlatformSurface _vulkanPlatformSurface;
+ private GRVkBackendContext _grVkBackend;
public VulkanRenderTarget(VulkanPlatformInterface vulkanPlatformInterface, IVulkanPlatformSurface vulkanPlatformSurface)
{
_surface = vulkanPlatformInterface.CreateRenderTarget(vulkanPlatformSurface);
+ _vulkanPlatformInterface = vulkanPlatformInterface;
_vulkanPlatformSurface = vulkanPlatformSurface;
+
+ Initialize();
+ }
+
+ private void Initialize()
+ {
+ GRVkGetProcedureAddressDelegate getProc = GetVulkanProcAddress;
+
+ _grVkBackend = new GRVkBackendContext()
+ {
+ VkInstance = _surface.Device.Handle,
+ VkPhysicalDevice = _vulkanPlatformInterface.PhysicalDevice.Handle,
+ VkDevice = _surface.Device.Handle,
+ VkQueue = _surface.Device.Queue.Handle,
+ GraphicsQueueIndex = _vulkanPlatformInterface.PhysicalDevice.QueueFamilyIndex,
+ GetProcedureAddress = getProc
+ };
+
+ GrContext = GRContext.CreateVulkan(_grVkBackend);
+
+ var gpu = AvaloniaLocator.Current.GetService<VulkanSkiaGpu>();
+
+ if (gpu.MaxResourceBytes.HasValue)
+ {
+ GrContext.SetResourceCacheLimit(gpu.MaxResourceBytes.Value);
+ }
+ }
+
+ private IntPtr GetVulkanProcAddress(string name, IntPtr instanceHandle, IntPtr deviceHandle)
+ {
+ IntPtr addr;
+
+ if (deviceHandle != IntPtr.Zero)
+ {
+ addr = _vulkanPlatformInterface.Api.GetDeviceProcAddr(new Device(deviceHandle), name);
+
+ if (addr != IntPtr.Zero)
+ {
+ return addr;
+ }
+
+ addr = _vulkanPlatformInterface.Api.GetDeviceProcAddr(new Device(_surface.Device.Handle), name);
+
+ if (addr != IntPtr.Zero)
+ {
+ return addr;
+ }
+ }
+
+ addr = _vulkanPlatformInterface.Api.GetInstanceProcAddr(new Instance(_vulkanPlatformInterface.Instance.Handle), name);
+
+ if (addr == IntPtr.Zero)
+ {
+ addr = _vulkanPlatformInterface.Api.GetInstanceProcAddr(new Instance(instanceHandle), name);
+ }
+
+ return addr;
}
public void Dispose()
{
+ _grVkBackend.Dispose();
+ GrContext.Dispose();
_surface.Dispose();
}
@@ -45,20 +109,22 @@ namespace Ryujinx.Ava.Ui.Backend.Vulkan
{
GrContext.ResetContext();
+ var image = _surface.GetImage();
+
var imageInfo = new GRVkImageInfo()
{
CurrentQueueFamily = disp.QueueFamilyIndex,
- Format = _surface.ImageFormat,
- Image = _surface.Image.Handle,
- ImageLayout = (uint)_surface.Image.CurrentLayout,
- ImageTiling = (uint)_surface.Image.Tiling,
+ Format = (uint)image.Format,
+ Image = image.Handle,
+ ImageLayout = (uint)image.CurrentLayout,
+ ImageTiling = (uint)image.Tiling,
ImageUsageFlags = _surface.UsageFlags,
LevelCount = _surface.MipLevels,
SampleCount = 1,
Protected = false,
Alloc = new GRVkAlloc()
{
- Memory = _surface.Image.MemoryHandle,
+ Memory = image.MemoryHandle,
Flags = 0,
Offset = 0,
Size = _surface.MemorySize
diff --git a/Ryujinx.Ava/Ui/Backend/Vulkan/Skia/VulkanSkiaGpu.cs b/Ryujinx.Ava/Ui/Backend/Vulkan/Skia/VulkanSkiaGpu.cs
index 4fc6b929..a5c27086 100644
--- a/Ryujinx.Ava/Ui/Backend/Vulkan/Skia/VulkanSkiaGpu.cs
+++ b/Ryujinx.Ava/Ui/Backend/Vulkan/Skia/VulkanSkiaGpu.cs
@@ -13,71 +13,12 @@ namespace Ryujinx.Ava.Ui.Backend.Vulkan
public class VulkanSkiaGpu : ISkiaGpu
{
private readonly VulkanPlatformInterface _vulkan;
- private readonly long? _maxResourceBytes;
- private GRVkBackendContext _grVkBackend;
- private bool _initialized;
-
- public GRContext GrContext { get; private set; }
+ public long? MaxResourceBytes { get; }
public VulkanSkiaGpu(long? maxResourceBytes)
{
_vulkan = AvaloniaLocator.Current.GetService<VulkanPlatformInterface>();
- _maxResourceBytes = maxResourceBytes;
- }
-
- private void Initialize()
- {
- if (_initialized)
- {
- return;
- }
-
- _initialized = true;
- GRVkGetProcedureAddressDelegate getProc = (string name, IntPtr instanceHandle, IntPtr deviceHandle) =>
- {
- IntPtr addr = IntPtr.Zero;
-
- if (deviceHandle != IntPtr.Zero)
- {
- addr = _vulkan.Device.Api.GetDeviceProcAddr(new Device(deviceHandle), name);
-
- if (addr != IntPtr.Zero)
- {
- return addr;
- }
-
- addr = _vulkan.Device.Api.GetDeviceProcAddr(new Device(_vulkan.Device.Handle), name);
-
- if (addr != IntPtr.Zero)
- {
- return addr;
- }
- }
-
- addr = _vulkan.Device.Api.GetInstanceProcAddr(new Instance(_vulkan.Instance.Handle), name);
-
- if (addr == IntPtr.Zero)
- {
- addr = _vulkan.Device.Api.GetInstanceProcAddr(new Instance(instanceHandle), name);
- }
-
- return addr;
- };
-
- _grVkBackend = new GRVkBackendContext()
- {
- VkInstance = _vulkan.Device.Handle,
- VkPhysicalDevice = _vulkan.PhysicalDevice.Handle,
- VkDevice = _vulkan.Device.Handle,
- VkQueue = _vulkan.Device.Queue.Handle,
- GraphicsQueueIndex = _vulkan.PhysicalDevice.QueueFamilyIndex,
- GetProcedureAddress = getProc
- };
- GrContext = GRContext.CreateVulkan(_grVkBackend);
- if (_maxResourceBytes.HasValue)
- {
- GrContext.SetResourceCacheLimit(_maxResourceBytes.Value);
- }
+ MaxResourceBytes = maxResourceBytes;
}
public ISkiaGpuRenderTarget TryCreateRenderTarget(IEnumerable<object> surfaces)
@@ -106,10 +47,6 @@ namespace Ryujinx.Ava.Ui.Backend.Vulkan
VulkanRenderTarget vulkanRenderTarget = new VulkanRenderTarget(_vulkan, window);
- Initialize();
-
- vulkanRenderTarget.GrContext = GrContext;
-
return vulkanRenderTarget;
}
diff --git a/Ryujinx.Ava/Ui/Backend/Vulkan/Surfaces/VulkanSurfaceRenderTarget.cs b/Ryujinx.Ava/Ui/Backend/Vulkan/Surfaces/VulkanSurfaceRenderTarget.cs
index b2b8843d..510e6724 100644
--- a/Ryujinx.Ava/Ui/Backend/Vulkan/Surfaces/VulkanSurfaceRenderTarget.cs
+++ b/Ryujinx.Ava/Ui/Backend/Vulkan/Surfaces/VulkanSurfaceRenderTarget.cs
@@ -1,5 +1,6 @@
using System;
using Avalonia;
+using Ryujinx.Graphics.Vulkan;
using Silk.NET.Vulkan;
namespace Ryujinx.Ava.Ui.Vulkan.Surfaces
@@ -7,24 +8,35 @@ namespace Ryujinx.Ava.Ui.Vulkan.Surfaces
internal class VulkanSurfaceRenderTarget : IDisposable
{
private readonly VulkanPlatformInterface _platformInterface;
-
private readonly Format _format;
- public VulkanImage Image { get; private set; }
- public bool IsCorrupted { get; private set; } = true;
+ private VulkanCommandBufferPool.VulkanCommandBuffer _commandBuffer;
+ private VulkanImage Image { get; set; }
+ private object _lock = new object();
public uint MipLevels => Image.MipLevels;
+ public VulkanDevice Device { get; }
public VulkanSurfaceRenderTarget(VulkanPlatformInterface platformInterface, VulkanSurface surface)
{
_platformInterface = platformInterface;
- Display = VulkanDisplay.CreateDisplay(platformInterface.Instance, platformInterface.Device,
- platformInterface.PhysicalDevice, surface);
+ var device = VulkanInitialization.CreateDevice(platformInterface.Api,
+ platformInterface.PhysicalDevice.InternalHandle,
+ platformInterface.PhysicalDevice.QueueFamilyIndex,
+ VulkanInitialization.GetSupportedExtensions(platformInterface.Api, platformInterface.PhysicalDevice.InternalHandle),
+ platformInterface.PhysicalDevice.QueueCount);
+
+ Device = new VulkanDevice(device, platformInterface.PhysicalDevice, platformInterface.Api);
+
+ Display = VulkanDisplay.CreateDisplay(
+ platformInterface.Instance,
+ Device,
+ platformInterface.PhysicalDevice,
+ surface);
Surface = surface;
// Skia seems to only create surfaces from images with unorm format
-
IsRgba = Display.SurfaceFormat.Format >= Format.R8G8B8A8Unorm &&
Display.SurfaceFormat.Format <= Format.R8G8B8A8Srgb;
@@ -33,13 +45,13 @@ namespace Ryujinx.Ava.Ui.Vulkan.Surfaces
public bool IsRgba { get; }
- public uint ImageFormat => (uint) _format;
+ public uint ImageFormat => (uint)_format;
public ulong MemorySize => Image.MemorySize;
- public VulkanDisplay Display { get; }
+ public VulkanDisplay Display { get; private set; }
- public VulkanSurface Surface { get; }
+ public VulkanSurface Surface { get; private set; }
public uint UsageFlags => Image.UsageFlags;
@@ -47,46 +59,76 @@ namespace Ryujinx.Ava.Ui.Vulkan.Surfaces
public void Dispose()
{
- _platformInterface.Device.WaitIdle();
- DestroyImage();
- Display?.Dispose();
- Surface?.Dispose();
+ lock (_lock)
+ {
+ DestroyImage();
+ Display?.Dispose();
+ Surface?.Dispose();
+ Device?.Dispose();
+
+ Display = null;
+ Surface = null;
+ }
}
public VulkanSurfaceRenderingSession BeginDraw(float scaling)
{
- var session = new VulkanSurfaceRenderingSession(Display, _platformInterface.Device, this, scaling);
-
- if (IsCorrupted)
+ if (Image == null)
{
- IsCorrupted = false;
- DestroyImage();
- CreateImage();
- }
- else
- {
- Image.TransitionLayout(ImageLayout.ColorAttachmentOptimal, AccessFlags.AccessNoneKhr);
+ RecreateImage();
}
+ _commandBuffer?.WaitForFence();
+ _commandBuffer = null;
+
+ var session = new VulkanSurfaceRenderingSession(Display, Device, this, scaling);
+
+ Image.TransitionLayout(ImageLayout.ColorAttachmentOptimal, AccessFlags.AccessNoneKhr);
+
return session;
}
- public void Invalidate()
+ public void RecreateImage()
{
- IsCorrupted = true;
+ DestroyImage();
+ CreateImage();
}
private void CreateImage()
{
Size = Display.Size;
- Image = new VulkanImage(_platformInterface.Device, _platformInterface.PhysicalDevice, _platformInterface.Device.CommandBufferPool, ImageFormat, Size);
+ Image = new VulkanImage(Device, _platformInterface.PhysicalDevice, Display.CommandBufferPool, ImageFormat, Size);
}
private void DestroyImage()
{
- _platformInterface.Device.WaitIdle();
+ _commandBuffer?.WaitForFence();
+ _commandBuffer = null;
Image?.Dispose();
+ Image = null;
+ }
+
+ public VulkanImage GetImage()
+ {
+ return Image;
+ }
+
+ public void EndDraw()
+ {
+ lock (_lock)
+ {
+ if (Display == null)
+ {
+ return;
+ }
+
+ _commandBuffer = Display.StartPresentation();
+
+ Display.BlitImageToCurrentImage(this, _commandBuffer.InternalHandle);
+
+ Display.EndPresentation(_commandBuffer);
+ }
}
}
}
diff --git a/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanCommandBufferPool.cs b/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanCommandBufferPool.cs
index 240035ca..a00ecf2b 100644
--- a/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanCommandBufferPool.cs
+++ b/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanCommandBufferPool.cs
@@ -10,6 +10,7 @@ namespace Ryujinx.Ava.Ui.Vulkan
private readonly CommandPool _commandPool;
private readonly List<VulkanCommandBuffer> _usedCommandBuffers = new();
+ private readonly object _lock = new object();
public unsafe VulkanCommandBufferPool(VulkanDevice device, VulkanPhysicalDevice physicalDevice)
{
@@ -36,9 +37,12 @@ namespace Ryujinx.Ava.Ui.Vulkan
Level = CommandBufferLevel.Primary
};
- _device.Api.AllocateCommandBuffers(_device.InternalHandle, commandBufferAllocateInfo, out var commandBuffer);
+ lock (_lock)
+ {
+ _device.Api.AllocateCommandBuffers(_device.InternalHandle, commandBufferAllocateInfo, out var commandBuffer);
- return commandBuffer;
+ return commandBuffer;
+ }
}
public VulkanCommandBuffer CreateCommandBuffer()
@@ -48,7 +52,7 @@ namespace Ryujinx.Ava.Ui.Vulkan
public void FreeUsedCommandBuffers()
{
- lock (_usedCommandBuffers)
+ lock (_lock)
{
foreach (var usedCommandBuffer in _usedCommandBuffers)
{
@@ -61,7 +65,7 @@ namespace Ryujinx.Ava.Ui.Vulkan
private void DisposeCommandBuffer(VulkanCommandBuffer commandBuffer)
{
- lock (_usedCommandBuffers)
+ lock (_lock)
{
_usedCommandBuffers.Add(commandBuffer);
}
@@ -69,8 +73,11 @@ namespace Ryujinx.Ava.Ui.Vulkan
public void Dispose()
{
- FreeUsedCommandBuffers();
- _device.Api.DestroyCommandPool(_device.InternalHandle, _commandPool, Span<AllocationCallbacks>.Empty);
+ lock (_lock)
+ {
+ FreeUsedCommandBuffers();
+ _device.Api.DestroyCommandPool(_device.InternalHandle, _commandPool, Span<AllocationCallbacks>.Empty);
+ }
}
public class VulkanCommandBuffer : IDisposable
@@ -80,6 +87,8 @@ namespace Ryujinx.Ava.Ui.Vulkan
private readonly Fence _fence;
private bool _hasEnded;
private bool _hasStarted;
+ private bool _isDisposed;
+ private object _lock = new object();
public IntPtr Handle => InternalHandle.Handle;
@@ -101,6 +110,22 @@ namespace Ryujinx.Ava.Ui.Vulkan
device.Api.CreateFence(device.InternalHandle, fenceCreateInfo, null, out _fence);
}
+ public void WaitForFence()
+ {
+ if (_isDisposed)
+ {
+ return;
+ }
+
+ lock (_lock)
+ {
+ if (!_isDisposed)
+ {
+ _device.Api.WaitForFences(_device.InternalHandle, 1, _fence, true, ulong.MaxValue);
+ }
+ }
+ }
+
public void BeginRecording()
{
if (!_hasStarted)
@@ -173,9 +198,17 @@ namespace Ryujinx.Ava.Ui.Vulkan
public void Dispose()
{
- _device.Api.WaitForFences(_device.InternalHandle, 1, _fence, true, ulong.MaxValue);
- _device.Api.FreeCommandBuffers(_device.InternalHandle, _commandBufferPool._commandPool, 1, InternalHandle);
- _device.Api.DestroyFence(_device.InternalHandle, _fence, Span<AllocationCallbacks>.Empty);
+ lock (_lock)
+ {
+ if (!_isDisposed)
+ {
+ _isDisposed = true;
+
+ _device.Api.WaitForFences(_device.InternalHandle, 1, _fence, true, ulong.MaxValue);
+ _device.Api.FreeCommandBuffers(_device.InternalHandle, _commandBufferPool._commandPool, 1, InternalHandle);
+ _device.Api.DestroyFence(_device.InternalHandle, _fence, Span<AllocationCallbacks>.Empty);
+ }
+ }
}
}
}
diff --git a/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanDevice.cs b/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanDevice.cs
index b03fd720..3d893e19 100644
--- a/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanDevice.cs
+++ b/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanDevice.cs
@@ -14,12 +14,9 @@ namespace Ryujinx.Ava.Ui.Vulkan
api.GetDeviceQueue(apiHandle, physicalDevice.QueueFamilyIndex, 0, out var queue);
- var vulkanQueue = new VulkanQueue(this, queue);
- Queue = vulkanQueue;
+ Queue = new VulkanQueue(this, queue);
- PresentQueue = vulkanQueue;
-
- CommandBufferPool = new VulkanCommandBufferPool(this, physicalDevice);
+ PresentQueue = Queue;
}
public IntPtr Handle => InternalHandle.Handle;
@@ -29,13 +26,12 @@ namespace Ryujinx.Ava.Ui.Vulkan
public VulkanQueue Queue { get; private set; }
public VulkanQueue PresentQueue { get; }
- public VulkanCommandBufferPool CommandBufferPool { get; }
public void Dispose()
{
WaitIdle();
- CommandBufferPool?.Dispose();
Queue = null;
+ Api.DestroyDevice(InternalHandle, Span<AllocationCallbacks>.Empty);
}
internal void Submit(SubmitInfo submitInfo, Fence fence = default)
diff --git a/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanDisplay.cs b/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanDisplay.cs
index bfe5b5a6..f3116fbd 100644
--- a/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanDisplay.cs
+++ b/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanDisplay.cs
@@ -3,7 +3,6 @@ using System.Linq;
using System.Threading;
using Avalonia;
using Ryujinx.Ava.Ui.Vulkan.Surfaces;
-using Ryujinx.Ui.Common.Configuration;
using Silk.NET.Vulkan;
using Silk.NET.Vulkan.Extensions.KHR;
@@ -15,16 +14,19 @@ namespace Ryujinx.Ava.Ui.Vulkan
private readonly VulkanInstance _instance;
private readonly VulkanPhysicalDevice _physicalDevice;
private readonly VulkanSemaphorePair _semaphorePair;
+ private readonly VulkanDevice _device;
private uint _nextImage;
private readonly VulkanSurface _surface;
private SurfaceFormatKHR _surfaceFormat;
private SwapchainKHR _swapchain;
private Extent2D _swapchainExtent;
private Image[] _swapchainImages;
- private VulkanDevice _device { get; }
- private ImageView[] _swapchainImageViews = new ImageView[0];
+ private ImageView[] _swapchainImageViews = Array.Empty<ImageView>();
private bool _vsyncStateChanged;
private bool _vsyncEnabled;
+ private bool _surfaceChanged;
+
+ public event EventHandler Presented;
public VulkanCommandBufferPool CommandBufferPool { get; set; }
@@ -73,6 +75,14 @@ namespace Ryujinx.Ava.Ui.Vulkan
CommandBufferPool.Dispose();
}
+ public bool IsSurfaceChanged()
+ {
+ var changed = _surfaceChanged;
+ _surfaceChanged = false;
+
+ return changed;
+ }
+
private static unsafe SwapchainKHR CreateSwapchain(VulkanInstance instance, VulkanDevice device,
VulkanPhysicalDevice physicalDevice, VulkanSurface surface, out Extent2D swapchainExtent,
SwapchainKHR? oldswapchain = null, bool vsyncEnabled = true)
@@ -193,22 +203,23 @@ namespace Ryujinx.Ava.Ui.Vulkan
}
var modes = presentModes.ToList();
- var presentMode = PresentModeKHR.PresentModeFifoKhr;
if (!vsyncEnabled && modes.Contains(PresentModeKHR.PresentModeImmediateKhr))
{
- presentMode = PresentModeKHR.PresentModeImmediateKhr;
+ return PresentModeKHR.PresentModeImmediateKhr;
}
else if (modes.Contains(PresentModeKHR.PresentModeMailboxKhr))
{
- presentMode = PresentModeKHR.PresentModeMailboxKhr;
+ return PresentModeKHR.PresentModeMailboxKhr;
}
- else if (modes.Contains(PresentModeKHR.PresentModeImmediateKhr))
+ else if (modes.Contains(PresentModeKHR.PresentModeFifoKhr))
{
- presentMode = PresentModeKHR.PresentModeImmediateKhr;
+ return PresentModeKHR.PresentModeFifoKhr;
+ }
+ else
+ {
+ return PresentModeKHR.PresentModeImmediateKhr;
}
-
- return presentMode;
}
internal static VulkanDisplay CreateDisplay(VulkanInstance instance, VulkanDevice device,
@@ -266,6 +277,8 @@ namespace Ryujinx.Ava.Ui.Vulkan
_swapchain = CreateSwapchain(_instance, _device, _physicalDevice, _surface, out _swapchainExtent, _swapchain, _vsyncEnabled);
CreateSwapchainImages();
+
+ _surfaceChanged = true;
}
private unsafe ImageView CreateSwapchainImageView(Image swapchainImage, Format format)
@@ -306,7 +319,7 @@ namespace Ryujinx.Ava.Ui.Vulkan
return true;
}
- internal VulkanCommandBufferPool.VulkanCommandBuffer StartPresentation(VulkanSurfaceRenderTarget renderTarget)
+ internal VulkanCommandBufferPool.VulkanCommandBuffer StartPresentation()
{
_nextImage = 0;
while (true)
@@ -346,8 +359,10 @@ namespace Ryujinx.Ava.Ui.Vulkan
internal void BlitImageToCurrentImage(VulkanSurfaceRenderTarget renderTarget, CommandBuffer commandBuffer)
{
+ var image = renderTarget.GetImage();
+
VulkanMemoryHelper.TransitionLayout(_device, commandBuffer,
- renderTarget.Image.InternalHandle.Value, (ImageLayout)renderTarget.Image.CurrentLayout,
+ image.InternalHandle.Value, (ImageLayout)image.CurrentLayout,
AccessFlags.AccessNoneKhr,
ImageLayout.TransferSrcOptimal,
AccessFlags.AccessTransferReadBit,
@@ -381,7 +396,7 @@ namespace Ryujinx.Ava.Ui.Vulkan
}
};
- _device.Api.CmdBlitImage(commandBuffer, renderTarget.Image.InternalHandle.Value,
+ _device.Api.CmdBlitImage(commandBuffer, image.InternalHandle.Value,
ImageLayout.TransferSrcOptimal,
_swapchainImages[_nextImage],
ImageLayout.TransferDstOptimal,
@@ -390,9 +405,9 @@ namespace Ryujinx.Ava.Ui.Vulkan
Filter.Linear);
VulkanMemoryHelper.TransitionLayout(_device, commandBuffer,
- renderTarget.Image.InternalHandle.Value, ImageLayout.TransferSrcOptimal,
+ image.InternalHandle.Value, ImageLayout.TransferSrcOptimal,
AccessFlags.AccessTransferReadBit,
- (ImageLayout)renderTarget.Image.CurrentLayout,
+ (ImageLayout)image.CurrentLayout,
AccessFlags.AccessNoneKhr,
renderTarget.MipLevels);
}
@@ -434,6 +449,8 @@ namespace Ryujinx.Ava.Ui.Vulkan
}
CommandBufferPool.FreeUsedCommandBuffers();
+
+ Presented?.Invoke(this, null);
}
}
}
diff --git a/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanImage.cs b/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanImage.cs
index 343ba760..3fbb8665 100644
--- a/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanImage.cs
+++ b/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanImage.cs
@@ -148,20 +148,18 @@ namespace Ryujinx.Ava.Ui.Vulkan
_currentAccessFlags = destinationAccessFlags;
}
- public void TransitionLayout(uint destinationLayout, uint destinationAccessFlags)
+ public void Dispose()
{
- TransitionLayout((ImageLayout)destinationLayout, (AccessFlags)destinationAccessFlags);
- }
-
- public unsafe void Dispose()
- {
- _device.Api.DestroyImageView(_device.InternalHandle, _imageView.Value, null);
- _device.Api.DestroyImage(_device.InternalHandle, InternalHandle.Value, null);
- _device.Api.FreeMemory(_device.InternalHandle, _imageMemory, null);
+ if (InternalHandle != null)
+ {
+ _device.Api.DestroyImageView(_device.InternalHandle, _imageView.Value, Span<AllocationCallbacks>.Empty);
+ _device.Api.DestroyImage(_device.InternalHandle, InternalHandle.Value, Span<AllocationCallbacks>.Empty);
+ _device.Api.FreeMemory(_device.InternalHandle, _imageMemory, Span<AllocationCallbacks>.Empty);
- _imageView = default;
- InternalHandle = default;
- _imageMemory = default;
+ _imageView = default;
+ InternalHandle = null;
+ _imageMemory = default;
+ }
}
}
}
diff --git a/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanInstance.cs b/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanInstance.cs
index a3a9ea61..b50e9c07 100644
--- a/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanInstance.cs
+++ b/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanInstance.cs
@@ -57,8 +57,7 @@ namespace Ryujinx.Ava.Ui.Vulkan
var applicationInfo = new ApplicationInfo
{
PApplicationName = (byte*)applicationName,
- ApiVersion = new Version32((uint)options.VulkanVersion.Major, (uint)options.VulkanVersion.Minor,
- (uint)options.VulkanVersion.Build),
+ ApiVersion = Vk.Version12.Value,
PEngineName = (byte*)engineName,
EngineVersion = new Version32(1, 0, 0),
ApplicationVersion = new Version32(1, 0, 0)
diff --git a/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanOptions.cs b/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanOptions.cs
index 8e836398..0027753c 100644
--- a/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanOptions.cs
+++ b/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanOptions.cs
@@ -12,11 +12,6 @@ namespace Ryujinx.Ava.Ui.Vulkan
public string ApplicationName { get; set; }
/// <summary>
- /// Specifies the Vulkan API version to use
- /// </summary>
- public Version VulkanVersion { get; set; } = new Version(1, 1, 0);
-
- /// <summary>
/// Specifies additional extensions to enable if available on the instance
/// </summary>
public IEnumerable<string> InstanceExtensions { get; set; } = Enumerable.Empty<string>();
diff --git a/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanPlatformInterface.cs b/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanPlatformInterface.cs
index 47a07949..ff8d9328 100644
--- a/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanPlatformInterface.cs
+++ b/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanPlatformInterface.cs
@@ -18,13 +18,11 @@ namespace Ryujinx.Ava.Ui.Vulkan
public VulkanPhysicalDevice PhysicalDevice { get; private set; }
public VulkanInstance Instance { get; }
- public VulkanDevice Device { get; set; }
public Vk Api { get; private set; }
public VulkanSurfaceRenderTarget MainSurface { get; set; }
public void Dispose()
{
- Device?.Dispose();
Instance?.Dispose();
Api?.Dispose();
}
@@ -54,16 +52,9 @@ namespace Ryujinx.Ava.Ui.Vulkan
{
var surface = VulkanSurface.CreateSurface(Instance, platformSurface);
- if (Device == null)
+ if (PhysicalDevice == null)
{
PhysicalDevice = VulkanPhysicalDevice.FindSuitablePhysicalDevice(Instance, surface, _options.PreferDiscreteGpu, _options.PreferredDevice);
- var device = VulkanInitialization.CreateDevice(Instance.Api,
- PhysicalDevice.InternalHandle,
- PhysicalDevice.QueueFamilyIndex,
- VulkanInitialization.GetSupportedExtensions(Instance.Api, PhysicalDevice.InternalHandle),
- PhysicalDevice.QueueCount);
-
- Device = new VulkanDevice(device, PhysicalDevice, Instance.Api);
}
var renderTarget = new VulkanSurfaceRenderTarget(this, surface);
@@ -71,7 +62,6 @@ namespace Ryujinx.Ava.Ui.Vulkan
if (MainSurface == null && surface != null)
{
MainSurface = renderTarget;
- MainSurface.Display.ChangeVSyncMode(false);
}
return renderTarget;
diff --git a/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanSurfaceRenderingSession.cs b/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanSurfaceRenderingSession.cs
index 8833ede5..71f5f18a 100644
--- a/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanSurfaceRenderingSession.cs
+++ b/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanSurfaceRenderingSession.cs
@@ -9,7 +9,6 @@ namespace Ryujinx.Ava.Ui.Vulkan
{
private readonly VulkanDevice _device;
private readonly VulkanSurfaceRenderTarget _renderTarget;
- private VulkanCommandBufferPool.VulkanCommandBuffer _commandBuffer;
public VulkanSurfaceRenderingSession(VulkanDisplay display, VulkanDevice device,
VulkanSurfaceRenderTarget renderTarget, float scaling)
@@ -32,17 +31,13 @@ namespace Ryujinx.Ava.Ui.Vulkan
{
if (!Display.EnsureSwapchainAvailable())
{
- _renderTarget.Invalidate();
+ _renderTarget.RecreateImage();
}
}
public void Dispose()
{
- _commandBuffer = Display.StartPresentation(_renderTarget);
-
- Display.BlitImageToCurrentImage(_renderTarget, _commandBuffer.InternalHandle);
-
- Display.EndPresentation(_commandBuffer);
+ _renderTarget.EndDraw();
}
}
}