forked from Mirror/Ryujinx
c8f9292bab
* 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
134 lines
3.9 KiB
C#
134 lines
3.9 KiB
C#
using System;
|
|
using Avalonia;
|
|
using Ryujinx.Graphics.Vulkan;
|
|
using Silk.NET.Vulkan;
|
|
|
|
namespace Ryujinx.Ava.Ui.Vulkan.Surfaces
|
|
{
|
|
internal class VulkanSurfaceRenderTarget : IDisposable
|
|
{
|
|
private readonly VulkanPlatformInterface _platformInterface;
|
|
private readonly Format _format;
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
_format = IsRgba ? Format.R8G8B8A8Unorm : Format.B8G8R8A8Unorm;
|
|
}
|
|
|
|
public bool IsRgba { get; }
|
|
|
|
public uint ImageFormat => (uint)_format;
|
|
|
|
public ulong MemorySize => Image.MemorySize;
|
|
|
|
public VulkanDisplay Display { get; private set; }
|
|
|
|
public VulkanSurface Surface { get; private set; }
|
|
|
|
public uint UsageFlags => Image.UsageFlags;
|
|
|
|
public PixelSize Size { get; private set; }
|
|
|
|
public void Dispose()
|
|
{
|
|
lock (_lock)
|
|
{
|
|
DestroyImage();
|
|
Display?.Dispose();
|
|
Surface?.Dispose();
|
|
Device?.Dispose();
|
|
|
|
Display = null;
|
|
Surface = null;
|
|
}
|
|
}
|
|
|
|
public VulkanSurfaceRenderingSession BeginDraw(float scaling)
|
|
{
|
|
if (Image == null)
|
|
{
|
|
RecreateImage();
|
|
}
|
|
|
|
_commandBuffer?.WaitForFence();
|
|
_commandBuffer = null;
|
|
|
|
var session = new VulkanSurfaceRenderingSession(Display, Device, this, scaling);
|
|
|
|
Image.TransitionLayout(ImageLayout.ColorAttachmentOptimal, AccessFlags.AccessNoneKhr);
|
|
|
|
return session;
|
|
}
|
|
|
|
public void RecreateImage()
|
|
{
|
|
DestroyImage();
|
|
CreateImage();
|
|
}
|
|
|
|
private void CreateImage()
|
|
{
|
|
Size = Display.Size;
|
|
|
|
Image = new VulkanImage(Device, _platformInterface.PhysicalDevice, Display.CommandBufferPool, ImageFormat, Size);
|
|
}
|
|
|
|
private void DestroyImage()
|
|
{
|
|
_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);
|
|
}
|
|
}
|
|
}
|
|
}
|