diff options
| author | riperiperi <rhy3756547@hotmail.com> | 2022-12-06 22:00:25 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-12-06 19:00:25 -0300 |
| commit | e211c3f00a847f50b286349918e5c51967862e93 (patch) | |
| tree | 5c703923741ee42362c86fef3981bdf745f881a4 /Ryujinx.Ava/Helper | |
| parent | d3709a753f88e6b02d6a1760835227a7fdcc5a19 (diff) | |
UI: Add Metal surface creation for MoltenVK (#3980)
* Initial implementation of metal surface across UIs
* Fix SDL2 on windows
* Update Ryujinx/Ryujinx.csproj
Co-authored-by: Mary-nyan <thog@protonmail.com>
* Address Feedback
Co-authored-by: Mary-nyan <thog@protonmail.com>
Diffstat (limited to 'Ryujinx.Ava/Helper')
| -rw-r--r-- | Ryujinx.Ava/Helper/MetalHelper.cs | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/Ryujinx.Ava/Helper/MetalHelper.cs b/Ryujinx.Ava/Helper/MetalHelper.cs new file mode 100644 index 00000000..ae07ce69 --- /dev/null +++ b/Ryujinx.Ava/Helper/MetalHelper.cs @@ -0,0 +1,127 @@ +using System; +using System.Runtime.Versioning; +using System.Runtime.InteropServices; +using Avalonia; + +namespace Ryujinx.Ava.Ui.Helper +{ + public delegate void UpdateBoundsCallbackDelegate(Rect rect); + + [SupportedOSPlatform("macos")] + static class MetalHelper + { + private const string LibObjCImport = "/usr/lib/libobjc.A.dylib"; + + private struct Selector + { + public readonly IntPtr NativePtr; + + public unsafe Selector(string value) + { + int size = System.Text.Encoding.UTF8.GetMaxByteCount(value.Length); + byte* data = stackalloc byte[size]; + + fixed (char* pValue = value) + { + System.Text.Encoding.UTF8.GetBytes(pValue, value.Length, data, size); + } + + NativePtr = sel_registerName(data); + } + + public static implicit operator Selector(string value) => new Selector(value); + } + + private static unsafe IntPtr GetClass(string value) + { + int size = System.Text.Encoding.UTF8.GetMaxByteCount(value.Length); + byte* data = stackalloc byte[size]; + + fixed (char* pValue = value) + { + System.Text.Encoding.UTF8.GetBytes(pValue, value.Length, data, size); + } + + return objc_getClass(data); + } + + private struct NSPoint + { + public double X; + public double Y; + + public NSPoint(double x, double y) + { + X = x; + Y = y; + } + } + + private struct NSRect + { + public NSPoint Pos; + public NSPoint Size; + + public NSRect(double x, double y, double width, double height) + { + Pos = new NSPoint(x, y); + Size = new NSPoint(width, height); + } + } + + public static IntPtr GetMetalLayer(out IntPtr nsView, out UpdateBoundsCallbackDelegate updateBounds) + { + // Create a new CAMetalLayer. + IntPtr layerClass = GetClass("CAMetalLayer"); + IntPtr metalLayer = IntPtr_objc_msgSend(layerClass, "alloc"); + objc_msgSend(metalLayer, "init"); + + // Create a child NSView to render into. + IntPtr nsViewClass = GetClass("NSView"); + IntPtr child = IntPtr_objc_msgSend(nsViewClass, "alloc"); + objc_msgSend(child, "init", new NSRect(0, 0, 0, 0)); + + // Make its renderer our metal layer. + objc_msgSend(child, "setWantsLayer:", (byte)1); + objc_msgSend(child, "setLayer:", metalLayer); + objc_msgSend(metalLayer, "setContentsScale:", Program.DesktopScaleFactor); + + // Ensure the scale factor is up to date. + updateBounds = (Rect rect) => { + objc_msgSend(metalLayer, "setContentsScale:", Program.DesktopScaleFactor); + }; + + nsView = child; + return metalLayer; + } + + public static void DestroyMetalLayer(IntPtr nsView, IntPtr metalLayer) + { + // TODO + } + + [DllImport(LibObjCImport)] + private static unsafe extern IntPtr sel_registerName(byte* data); + + [DllImport(LibObjCImport)] + private static unsafe extern IntPtr objc_getClass(byte* data); + + [DllImport(LibObjCImport)] + private static extern void objc_msgSend(IntPtr receiver, Selector selector); + + [DllImport(LibObjCImport)] + private static extern void objc_msgSend(IntPtr receiver, Selector selector, byte value); + + [DllImport(LibObjCImport)] + private static extern void objc_msgSend(IntPtr receiver, Selector selector, IntPtr value); + + [DllImport(LibObjCImport)] + private static extern void objc_msgSend(IntPtr receiver, Selector selector, NSRect point); + + [DllImport(LibObjCImport)] + private static extern void objc_msgSend(IntPtr receiver, Selector selector, double value); + + [DllImport(LibObjCImport, EntryPoint = "objc_msgSend")] + private static extern IntPtr IntPtr_objc_msgSend(IntPtr receiver, Selector selector); + } +}
\ No newline at end of file |
