MetalHelper.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. using Gdk;
  2. using System;
  3. using System.Runtime.InteropServices;
  4. using System.Runtime.Versioning;
  5. namespace Ryujinx.UI.Helper
  6. {
  7. public delegate void UpdateBoundsCallbackDelegate(Window window);
  8. [SupportedOSPlatform("macos")]
  9. static partial class MetalHelper
  10. {
  11. private const string LibObjCImport = "/usr/lib/libobjc.A.dylib";
  12. private readonly struct Selector
  13. {
  14. public readonly IntPtr NativePtr;
  15. public unsafe Selector(string value)
  16. {
  17. int size = System.Text.Encoding.UTF8.GetMaxByteCount(value.Length);
  18. byte* data = stackalloc byte[size];
  19. fixed (char* pValue = value)
  20. {
  21. System.Text.Encoding.UTF8.GetBytes(pValue, value.Length, data, size);
  22. }
  23. NativePtr = sel_registerName(data);
  24. }
  25. public static implicit operator Selector(string value) => new(value);
  26. }
  27. private static unsafe IntPtr GetClass(string value)
  28. {
  29. int size = System.Text.Encoding.UTF8.GetMaxByteCount(value.Length);
  30. byte* data = stackalloc byte[size];
  31. fixed (char* pValue = value)
  32. {
  33. System.Text.Encoding.UTF8.GetBytes(pValue, value.Length, data, size);
  34. }
  35. return objc_getClass(data);
  36. }
  37. private struct NsPoint
  38. {
  39. public double X;
  40. public double Y;
  41. public NsPoint(double x, double y)
  42. {
  43. X = x;
  44. Y = y;
  45. }
  46. }
  47. private struct NsRect
  48. {
  49. public NsPoint Pos;
  50. public NsPoint Size;
  51. public NsRect(double x, double y, double width, double height)
  52. {
  53. Pos = new NsPoint(x, y);
  54. Size = new NsPoint(width, height);
  55. }
  56. }
  57. public static IntPtr GetMetalLayer(Display display, Window window, out IntPtr nsView, out UpdateBoundsCallbackDelegate updateBounds)
  58. {
  59. nsView = gdk_quartz_window_get_nsview(window.Handle);
  60. // Create a new CAMetalLayer.
  61. IntPtr layerClass = GetClass("CAMetalLayer");
  62. IntPtr metalLayer = IntPtr_objc_msgSend(layerClass, "alloc");
  63. objc_msgSend(metalLayer, "init");
  64. // Create a child NSView to render into.
  65. IntPtr nsViewClass = GetClass("NSView");
  66. IntPtr child = IntPtr_objc_msgSend(nsViewClass, "alloc");
  67. objc_msgSend(child, "init", new NsRect());
  68. // Add it as a child.
  69. objc_msgSend(nsView, "addSubview:", child);
  70. // Make its renderer our metal layer.
  71. objc_msgSend(child, "setWantsLayer:", (byte)1);
  72. objc_msgSend(child, "setLayer:", metalLayer);
  73. objc_msgSend(metalLayer, "setContentsScale:", (double)display.GetMonitorAtWindow(window).ScaleFactor);
  74. // Set the frame position/location.
  75. updateBounds = (Window window) =>
  76. {
  77. window.GetPosition(out int x, out int y);
  78. int width = window.Width;
  79. int height = window.Height;
  80. objc_msgSend(child, "setFrame:", new NsRect(x, y, width, height));
  81. };
  82. updateBounds(window);
  83. return metalLayer;
  84. }
  85. [LibraryImport(LibObjCImport)]
  86. private static unsafe partial IntPtr sel_registerName(byte* data);
  87. [LibraryImport(LibObjCImport)]
  88. private static unsafe partial IntPtr objc_getClass(byte* data);
  89. [LibraryImport(LibObjCImport)]
  90. private static partial void objc_msgSend(IntPtr receiver, Selector selector);
  91. [LibraryImport(LibObjCImport)]
  92. private static partial void objc_msgSend(IntPtr receiver, Selector selector, byte value);
  93. [LibraryImport(LibObjCImport)]
  94. private static partial void objc_msgSend(IntPtr receiver, Selector selector, IntPtr value);
  95. [LibraryImport(LibObjCImport)]
  96. private static partial void objc_msgSend(IntPtr receiver, Selector selector, NsRect point);
  97. [LibraryImport(LibObjCImport)]
  98. private static partial void objc_msgSend(IntPtr receiver, Selector selector, double value);
  99. [LibraryImport(LibObjCImport, EntryPoint = "objc_msgSend")]
  100. private static partial IntPtr IntPtr_objc_msgSend(IntPtr receiver, Selector selector);
  101. [LibraryImport("libgdk-3.0.dylib")]
  102. private static partial IntPtr gdk_quartz_window_get_nsview(IntPtr gdkWindow);
  103. }
  104. }