VulkanSurfaceRenderTarget.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. using System;
  2. using Avalonia;
  3. using Ryujinx.Graphics.Vulkan;
  4. using Silk.NET.Vulkan;
  5. namespace Ryujinx.Ava.Ui.Vulkan.Surfaces
  6. {
  7. internal class VulkanSurfaceRenderTarget : IDisposable
  8. {
  9. private readonly VulkanPlatformInterface _platformInterface;
  10. private readonly Format _format;
  11. private VulkanCommandBufferPool.VulkanCommandBuffer _commandBuffer;
  12. private VulkanImage Image { get; set; }
  13. private object _lock = new object();
  14. public uint MipLevels => Image.MipLevels;
  15. public VulkanDevice Device { get; }
  16. public VulkanSurfaceRenderTarget(VulkanPlatformInterface platformInterface, VulkanSurface surface)
  17. {
  18. _platformInterface = platformInterface;
  19. var device = VulkanInitialization.CreateDevice(platformInterface.Api,
  20. platformInterface.PhysicalDevice.InternalHandle,
  21. platformInterface.PhysicalDevice.QueueFamilyIndex,
  22. VulkanInitialization.GetSupportedExtensions(platformInterface.Api, platformInterface.PhysicalDevice.InternalHandle),
  23. platformInterface.PhysicalDevice.QueueCount);
  24. Device = new VulkanDevice(device, platformInterface.PhysicalDevice, platformInterface.Api);
  25. Display = VulkanDisplay.CreateDisplay(
  26. platformInterface.Instance,
  27. Device,
  28. platformInterface.PhysicalDevice,
  29. surface);
  30. Surface = surface;
  31. // Skia seems to only create surfaces from images with unorm format
  32. IsRgba = Display.SurfaceFormat.Format >= Format.R8G8B8A8Unorm &&
  33. Display.SurfaceFormat.Format <= Format.R8G8B8A8Srgb;
  34. _format = IsRgba ? Format.R8G8B8A8Unorm : Format.B8G8R8A8Unorm;
  35. }
  36. public bool IsRgba { get; }
  37. public uint ImageFormat => (uint)_format;
  38. public ulong MemorySize => Image.MemorySize;
  39. public VulkanDisplay Display { get; private set; }
  40. public VulkanSurface Surface { get; private set; }
  41. public uint UsageFlags => Image.UsageFlags;
  42. public PixelSize Size { get; private set; }
  43. public void Dispose()
  44. {
  45. lock (_lock)
  46. {
  47. DestroyImage();
  48. Display?.Dispose();
  49. Surface?.Dispose();
  50. Device?.Dispose();
  51. Display = null;
  52. Surface = null;
  53. }
  54. }
  55. public VulkanSurfaceRenderingSession BeginDraw(float scaling)
  56. {
  57. if (Image == null)
  58. {
  59. RecreateImage();
  60. }
  61. _commandBuffer?.WaitForFence();
  62. _commandBuffer = null;
  63. var session = new VulkanSurfaceRenderingSession(Display, Device, this, scaling);
  64. Image.TransitionLayout(ImageLayout.ColorAttachmentOptimal, AccessFlags.AccessNoneKhr);
  65. return session;
  66. }
  67. public void RecreateImage()
  68. {
  69. DestroyImage();
  70. CreateImage();
  71. }
  72. private void CreateImage()
  73. {
  74. Size = Display.Size;
  75. Image = new VulkanImage(Device, _platformInterface.PhysicalDevice, Display.CommandBufferPool, ImageFormat, Size);
  76. }
  77. private void DestroyImage()
  78. {
  79. _commandBuffer?.WaitForFence();
  80. _commandBuffer = null;
  81. Image?.Dispose();
  82. Image = null;
  83. }
  84. public VulkanImage GetImage()
  85. {
  86. return Image;
  87. }
  88. public void EndDraw()
  89. {
  90. lock (_lock)
  91. {
  92. if (Display == null)
  93. {
  94. return;
  95. }
  96. _commandBuffer = Display.StartPresentation();
  97. Display.BlitImageToCurrentImage(this, _commandBuffer.InternalHandle);
  98. Display.EndPresentation(_commandBuffer);
  99. }
  100. }
  101. }
  102. }