diff options
Diffstat (limited to 'Ryujinx.Ava/Ui/Backend/Vulkan/Skia/VulkanRenderTarget.cs')
-rw-r--r-- | Ryujinx.Ava/Ui/Backend/Vulkan/Skia/VulkanRenderTarget.cs | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/Ryujinx.Ava/Ui/Backend/Vulkan/Skia/VulkanRenderTarget.cs b/Ryujinx.Ava/Ui/Backend/Vulkan/Skia/VulkanRenderTarget.cs new file mode 100644 index 00000000..ba7ddc7a --- /dev/null +++ b/Ryujinx.Ava/Ui/Backend/Vulkan/Skia/VulkanRenderTarget.cs @@ -0,0 +1,135 @@ +using System; +using Avalonia.Skia; +using Ryujinx.Ava.Ui.Vulkan; +using Ryujinx.Ava.Ui.Vulkan.Surfaces; +using SkiaSharp; + +namespace Ryujinx.Ava.Ui.Backend.Vulkan +{ + internal class VulkanRenderTarget : ISkiaGpuRenderTarget + { + public GRContext GrContext { get; set; } + + private readonly VulkanSurfaceRenderTarget _surface; + private readonly IVulkanPlatformSurface _vulkanPlatformSurface; + + public VulkanRenderTarget(VulkanPlatformInterface vulkanPlatformInterface, IVulkanPlatformSurface vulkanPlatformSurface) + { + _surface = vulkanPlatformInterface.CreateRenderTarget(vulkanPlatformSurface); + _vulkanPlatformSurface = vulkanPlatformSurface; + } + + public void Dispose() + { + _surface.Dispose(); + } + + public ISkiaGpuRenderSession BeginRenderingSession() + { + var session = _surface.BeginDraw(_vulkanPlatformSurface.Scaling); + bool success = false; + try + { + var disp = session.Display; + var api = session.Api; + + var size = session.Size; + var scaling = session.Scaling; + if (size.Width <= 0 || size.Height <= 0 || scaling < 0) + { + size = new Avalonia.PixelSize(1, 1); + scaling = 1; + } + + lock (GrContext) + { + GrContext.ResetContext(); + + var imageInfo = new GRVkImageInfo() + { + CurrentQueueFamily = disp.QueueFamilyIndex, + Format = _surface.ImageFormat, + Image = _surface.Image.Handle, + ImageLayout = (uint)_surface.Image.CurrentLayout, + ImageTiling = (uint)_surface.Image.Tiling, + ImageUsageFlags = _surface.UsageFlags, + LevelCount = _surface.MipLevels, + SampleCount = 1, + Protected = false, + Alloc = new GRVkAlloc() + { + Memory = _surface.Image.MemoryHandle, + Flags = 0, + Offset = 0, + Size = _surface.MemorySize + } + }; + + var renderTarget = + new GRBackendRenderTarget((int)size.Width, (int)size.Height, 1, + imageInfo); + var surface = SKSurface.Create(GrContext, renderTarget, + GRSurfaceOrigin.TopLeft, + _surface.IsRgba ? SKColorType.Rgba8888 : SKColorType.Bgra8888, SKColorSpace.CreateSrgb()); + + if (surface == null) + { + throw new InvalidOperationException( + "Surface can't be created with the provided render target"); + } + + success = true; + + return new VulkanGpuSession(GrContext, renderTarget, surface, session); + } + } + finally + { + if (!success) + { + session.Dispose(); + } + } + } + + public bool IsCorrupted { get; } + + internal class VulkanGpuSession : ISkiaGpuRenderSession + { + private readonly GRBackendRenderTarget _backendRenderTarget; + private readonly VulkanSurfaceRenderingSession _vulkanSession; + + public VulkanGpuSession(GRContext grContext, + GRBackendRenderTarget backendRenderTarget, + SKSurface surface, + VulkanSurfaceRenderingSession vulkanSession) + { + GrContext = grContext; + _backendRenderTarget = backendRenderTarget; + SkSurface = surface; + _vulkanSession = vulkanSession; + + SurfaceOrigin = GRSurfaceOrigin.TopLeft; + } + + public void Dispose() + { + lock (_vulkanSession.Display.Lock) + { + SkSurface.Canvas.Flush(); + + SkSurface.Dispose(); + _backendRenderTarget.Dispose(); + GrContext.Flush(); + + _vulkanSession.Dispose(); + } + } + + public GRContext GrContext { get; } + public SKSurface SkSurface { get; } + public double ScaleFactor => _vulkanSession.Scaling; + public GRSurfaceOrigin SurfaceOrigin { get; } + } + } +} |