VulkanRenderTarget.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. using System;
  2. using Avalonia;
  3. using Avalonia.Skia;
  4. using Ryujinx.Ava.Ui.Vulkan;
  5. using Ryujinx.Ava.Ui.Vulkan.Surfaces;
  6. using Silk.NET.Vulkan;
  7. using SkiaSharp;
  8. namespace Ryujinx.Ava.Ui.Backend.Vulkan
  9. {
  10. internal class VulkanRenderTarget : ISkiaGpuRenderTarget
  11. {
  12. public GRContext GrContext { get; private set; }
  13. private readonly VulkanSurfaceRenderTarget _surface;
  14. private readonly VulkanPlatformInterface _vulkanPlatformInterface;
  15. private readonly IVulkanPlatformSurface _vulkanPlatformSurface;
  16. private GRVkBackendContext _grVkBackend;
  17. public VulkanRenderTarget(VulkanPlatformInterface vulkanPlatformInterface, IVulkanPlatformSurface vulkanPlatformSurface)
  18. {
  19. _surface = vulkanPlatformInterface.CreateRenderTarget(vulkanPlatformSurface);
  20. _vulkanPlatformInterface = vulkanPlatformInterface;
  21. _vulkanPlatformSurface = vulkanPlatformSurface;
  22. Initialize();
  23. }
  24. private void Initialize()
  25. {
  26. GRVkGetProcedureAddressDelegate getProc = GetVulkanProcAddress;
  27. _grVkBackend = new GRVkBackendContext()
  28. {
  29. VkInstance = _surface.Device.Handle,
  30. VkPhysicalDevice = _vulkanPlatformInterface.PhysicalDevice.Handle,
  31. VkDevice = _surface.Device.Handle,
  32. VkQueue = _surface.Device.Queue.Handle,
  33. GraphicsQueueIndex = _vulkanPlatformInterface.PhysicalDevice.QueueFamilyIndex,
  34. GetProcedureAddress = getProc
  35. };
  36. GrContext = GRContext.CreateVulkan(_grVkBackend);
  37. var gpu = AvaloniaLocator.Current.GetService<VulkanSkiaGpu>();
  38. if (gpu.MaxResourceBytes.HasValue)
  39. {
  40. GrContext.SetResourceCacheLimit(gpu.MaxResourceBytes.Value);
  41. }
  42. }
  43. private IntPtr GetVulkanProcAddress(string name, IntPtr instanceHandle, IntPtr deviceHandle)
  44. {
  45. IntPtr addr;
  46. if (deviceHandle != IntPtr.Zero)
  47. {
  48. addr = _vulkanPlatformInterface.Api.GetDeviceProcAddr(new Device(deviceHandle), name);
  49. if (addr != IntPtr.Zero)
  50. {
  51. return addr;
  52. }
  53. addr = _vulkanPlatformInterface.Api.GetDeviceProcAddr(new Device(_surface.Device.Handle), name);
  54. if (addr != IntPtr.Zero)
  55. {
  56. return addr;
  57. }
  58. }
  59. addr = _vulkanPlatformInterface.Api.GetInstanceProcAddr(new Instance(_vulkanPlatformInterface.Instance.Handle), name);
  60. if (addr == IntPtr.Zero)
  61. {
  62. addr = _vulkanPlatformInterface.Api.GetInstanceProcAddr(new Instance(instanceHandle), name);
  63. }
  64. return addr;
  65. }
  66. public void Dispose()
  67. {
  68. _grVkBackend.Dispose();
  69. GrContext.Dispose();
  70. _surface.Dispose();
  71. }
  72. public ISkiaGpuRenderSession BeginRenderingSession()
  73. {
  74. var session = _surface.BeginDraw(_vulkanPlatformSurface.Scaling);
  75. bool success = false;
  76. try
  77. {
  78. var disp = session.Display;
  79. var api = session.Api;
  80. var size = session.Size;
  81. var scaling = session.Scaling;
  82. if (size.Width <= 0 || size.Height <= 0 || scaling < 0)
  83. {
  84. size = new Avalonia.PixelSize(1, 1);
  85. scaling = 1;
  86. }
  87. lock (GrContext)
  88. {
  89. GrContext.ResetContext();
  90. var image = _surface.GetImage();
  91. var imageInfo = new GRVkImageInfo()
  92. {
  93. CurrentQueueFamily = disp.QueueFamilyIndex,
  94. Format = (uint)image.Format,
  95. Image = image.Handle,
  96. ImageLayout = (uint)image.CurrentLayout,
  97. ImageTiling = (uint)image.Tiling,
  98. ImageUsageFlags = _surface.UsageFlags,
  99. LevelCount = _surface.MipLevels,
  100. SampleCount = 1,
  101. Protected = false,
  102. Alloc = new GRVkAlloc()
  103. {
  104. Memory = image.MemoryHandle,
  105. Flags = 0,
  106. Offset = 0,
  107. Size = _surface.MemorySize
  108. }
  109. };
  110. var renderTarget =
  111. new GRBackendRenderTarget((int)size.Width, (int)size.Height, 1,
  112. imageInfo);
  113. var surface = SKSurface.Create(GrContext, renderTarget,
  114. GRSurfaceOrigin.TopLeft,
  115. _surface.IsRgba ? SKColorType.Rgba8888 : SKColorType.Bgra8888, SKColorSpace.CreateSrgb());
  116. if (surface == null)
  117. {
  118. throw new InvalidOperationException(
  119. "Surface can't be created with the provided render target");
  120. }
  121. success = true;
  122. return new VulkanGpuSession(GrContext, renderTarget, surface, session);
  123. }
  124. }
  125. finally
  126. {
  127. if (!success)
  128. {
  129. session.Dispose();
  130. }
  131. }
  132. }
  133. public bool IsCorrupted { get; }
  134. internal class VulkanGpuSession : ISkiaGpuRenderSession
  135. {
  136. private readonly GRBackendRenderTarget _backendRenderTarget;
  137. private readonly VulkanSurfaceRenderingSession _vulkanSession;
  138. public VulkanGpuSession(GRContext grContext,
  139. GRBackendRenderTarget backendRenderTarget,
  140. SKSurface surface,
  141. VulkanSurfaceRenderingSession vulkanSession)
  142. {
  143. GrContext = grContext;
  144. _backendRenderTarget = backendRenderTarget;
  145. SkSurface = surface;
  146. _vulkanSession = vulkanSession;
  147. SurfaceOrigin = GRSurfaceOrigin.TopLeft;
  148. }
  149. public void Dispose()
  150. {
  151. lock (_vulkanSession.Display.Lock)
  152. {
  153. SkSurface.Canvas.Flush();
  154. SkSurface.Dispose();
  155. _backendRenderTarget.Dispose();
  156. GrContext.Flush();
  157. _vulkanSession.Dispose();
  158. }
  159. }
  160. public GRContext GrContext { get; }
  161. public SKSurface SkSurface { get; }
  162. public double ScaleFactor => _vulkanSession.Scaling;
  163. public GRSurfaceOrigin SurfaceOrigin { get; }
  164. }
  165. }
  166. }