MetalHelper.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. using Gdk;
  2. using System;
  3. using System.Runtime.Versioning;
  4. using System.Runtime.InteropServices;
  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 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 Selector(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. window.GetPosition(out int x, out int y);
  77. int width = window.Width;
  78. int height = window.Height;
  79. objc_msgSend(child, "setFrame:", new NSRect(x, y, width, height));
  80. };
  81. updateBounds(window);
  82. return metalLayer;
  83. }
  84. [LibraryImport(LibObjCImport)]
  85. private static unsafe partial IntPtr sel_registerName(byte* data);
  86. [LibraryImport(LibObjCImport)]
  87. private static unsafe partial IntPtr objc_getClass(byte* data);
  88. [LibraryImport(LibObjCImport)]
  89. private static partial void objc_msgSend(IntPtr receiver, Selector selector);
  90. [LibraryImport(LibObjCImport)]
  91. private static partial void objc_msgSend(IntPtr receiver, Selector selector, byte value);
  92. [LibraryImport(LibObjCImport)]
  93. private static partial void objc_msgSend(IntPtr receiver, Selector selector, IntPtr value);
  94. [LibraryImport(LibObjCImport)]
  95. private static partial void objc_msgSend(IntPtr receiver, Selector selector, NSRect point);
  96. [LibraryImport(LibObjCImport)]
  97. private static partial void objc_msgSend(IntPtr receiver, Selector selector, double value);
  98. [LibraryImport(LibObjCImport, EntryPoint = "objc_msgSend")]
  99. private static partial IntPtr IntPtr_objc_msgSend(IntPtr receiver, Selector selector);
  100. [LibraryImport("libgdk-3.0.dylib")]
  101. private static partial IntPtr gdk_quartz_window_get_nsview(IntPtr gdkWindow);
  102. }
  103. }