aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Ava/Ui/Backend/Vulkan/Surfaces/VulkanSurfaceRenderTarget.cs
blob: b2b8843d29e9fd919961479a692c7de937f10906 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
using System;
using Avalonia;
using Silk.NET.Vulkan;

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;

        public uint MipLevels => Image.MipLevels;

        public VulkanSurfaceRenderTarget(VulkanPlatformInterface platformInterface, VulkanSurface surface)
        {
            _platformInterface = platformInterface;

            Display = VulkanDisplay.CreateDisplay(platformInterface.Instance, platformInterface.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; }

        public VulkanSurface Surface { get; }

        public uint UsageFlags => Image.UsageFlags;

        public PixelSize Size { get; private set; }

        public void Dispose()
        {
            _platformInterface.Device.WaitIdle();
            DestroyImage();
            Display?.Dispose();
            Surface?.Dispose();
        }

        public VulkanSurfaceRenderingSession BeginDraw(float scaling)
        {
            var session = new VulkanSurfaceRenderingSession(Display, _platformInterface.Device, this, scaling);

            if (IsCorrupted)
            {
                IsCorrupted = false;
                DestroyImage();
                CreateImage();
            }
            else
            {
                Image.TransitionLayout(ImageLayout.ColorAttachmentOptimal, AccessFlags.AccessNoneKhr);
            }

            return session;
        }

        public void Invalidate()
        {
            IsCorrupted = true;
        }

        private void CreateImage()
        {
            Size = Display.Size;

            Image = new VulkanImage(_platformInterface.Device, _platformInterface.PhysicalDevice, _platformInterface.Device.CommandBufferPool, ImageFormat, Size);
        }

        private void DestroyImage()
        {
            _platformInterface.Device.WaitIdle();
            Image?.Dispose();
        }
    }
}