add nativaot libryujinx project

This commit is contained in:
Emmanuel Hansen 2023-06-25 12:20:05 +00:00
parent 534f467d48
commit 6398b011a5
13 changed files with 1530 additions and 3 deletions

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenTK" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace LibRyujinx.Sample
{
internal static class LibRyujinxInterop
{
private const string dll = "LibRyujinx.Shared.dll";
[DllImport(dll, EntryPoint = "initialize")]
public extern static bool Initialize(IntPtr path);
[DllImport(dll, EntryPoint = "graphics_initialize")]
public extern static bool InitializeGraphics(GraphicsConfiguration graphicsConfiguration);
[DllImport(dll, EntryPoint = "device_initialize")]
internal extern static bool InitializeDevice();
[DllImport(dll, EntryPoint = "graphics_initialize_renderer")]
internal extern static bool InitializeGraphicsRenderer(GraphicsBackend backend, NativeGraphicsInterop nativeGraphicsInterop);
[DllImport(dll, EntryPoint = "device_load")]
internal extern static bool LoadApplication(IntPtr pathPtr);
[DllImport(dll, EntryPoint = "graphics_renderer_run_loop")]
internal extern static void RunLoop();
[DllImport(dll, EntryPoint = "graphics_renderer_set_size")]
internal extern static void SetRendererSize(int width, int height);
[DllImport(dll, EntryPoint = "graphics_renderer_set_swap_buffer_callback")]
internal extern static void SetSwapBuffersCallback(IntPtr swapBuffers);
[DllImport(dll, EntryPoint = "graphics_renderer_set_vsync")]
internal extern static void SetVsyncState(bool enabled);
}
[StructLayout(LayoutKind.Sequential)]
public struct GraphicsConfiguration
{
public float ResScale = 1f;
public float MaxAnisotropy = -1;
public bool FastGpuTime = true;
public bool Fast2DCopy = true;
public bool EnableMacroJit = false;
public bool EnableMacroHLE = true;
public bool EnableShaderCache = true;
public bool EnableSpirvCompilationOnVulkan = true;
public bool EnableTextureRecompression = false;
public BackendThreading BackendThreading = BackendThreading.Auto;
public GraphicsConfiguration()
{
}
}
public enum GraphicsBackend
{
Vulkan,
OpenGl
}
public enum BackendThreading
{
Auto,
Off,
On
}
public struct NativeGraphicsInterop
{
public IntPtr GlGetProcAddress;
public IntPtr VkNativeContextLoader;
public IntPtr VkCreateSurface;
public IntPtr VkRequiredExtensions;
public int VkRequiredExtensionsCount;
}
}

View file

@ -0,0 +1,115 @@
using LibRyujinx.Sample;
using OpenTK.Graphics.OpenGL;
using OpenTK.Windowing.Desktop;
using OpenTK.Windowing.GraphicsLibraryFramework;
using System.Runtime.InteropServices;
namespace LibRyujinx.NativeSample
{
internal class NativeWindow : OpenTK.Windowing.Desktop.NativeWindow
{
private nint del;
public delegate void SwapBuffersCallback();
public delegate IntPtr GetProcAddress(string name);
public delegate IntPtr CreateSurface(IntPtr instance);
private bool _isVulkan;
public NativeWindow(NativeWindowSettings nativeWindowSettings) : base(nativeWindowSettings)
{
_isVulkan = true;
}
internal unsafe void Start(string gamePath)
{
if (!_isVulkan)
{
MakeCurrent();
}
var getProcAddress = Marshal.GetFunctionPointerForDelegate<GetProcAddress>(x => GLFW.GetProcAddress(x));
var createSurface = Marshal.GetFunctionPointerForDelegate<CreateSurface>( x =>
{
VkHandle surface;
GLFW.CreateWindowSurface(new VkHandle(x) ,this.WindowPtr, null, out surface);
return surface.Handle;
});
var vkExtensions = GLFW.GetRequiredInstanceExtensions();
var pointers = new IntPtr[vkExtensions.Length];
for (int i = 0; i < vkExtensions.Length; i++)
{
pointers[i] = Marshal.StringToHGlobalAnsi(vkExtensions[i]);
}
fixed (IntPtr* ptr = pointers)
{
var nativeGraphicsInterop = new NativeGraphicsInterop()
{
GlGetProcAddress = getProcAddress,
VkRequiredExtensions = (nint)ptr,
VkRequiredExtensionsCount = pointers.Length,
VkCreateSurface = createSurface
};
var success = LibRyujinxInterop.InitializeGraphicsRenderer(_isVulkan ? GraphicsBackend.Vulkan : GraphicsBackend.OpenGl, nativeGraphicsInterop);
success = LibRyujinxInterop.InitializeDevice();
var path = Marshal.StringToHGlobalAnsi(gamePath);
var loaded = LibRyujinxInterop.LoadApplication(path);
LibRyujinxInterop.SetRendererSize(Size.X, Size.Y);
Marshal.FreeHGlobal(path);
}
if (!_isVulkan)
{
Context.MakeNoneCurrent();
}
var thread = new Thread(new ThreadStart(RunLoop));
thread.Start();
thread.Join();
foreach(var ptr in pointers)
{
Marshal.FreeHGlobal(ptr);
}
}
public void RunLoop()
{
del = Marshal.GetFunctionPointerForDelegate<SwapBuffersCallback>(SwapBuffers);
LibRyujinxInterop.SetSwapBuffersCallback(del);
if (!_isVulkan)
{
MakeCurrent();
Context.SwapInterval = 0;
}
Task.Run(async () =>
{
await Task.Delay(1000);
LibRyujinxInterop.SetVsyncState(false);
});
LibRyujinxInterop.RunLoop();
if (!_isVulkan)
{
Context.MakeNoneCurrent();
}
}
private void SwapBuffers()
{
if (!_isVulkan)
{
this.Context.SwapBuffers();
}
}
}
}

View file

@ -0,0 +1,33 @@
using LibRyujinx.Sample;
using OpenTK.Mathematics;
using OpenTK.Windowing.Common;
using OpenTK.Windowing.Desktop;
namespace LibRyujinx.NativeSample
{
internal class Program
{
static void Main(string[] args)
{
if (args.Length > 0)
{
var success = LibRyujinxInterop.Initialize(IntPtr.Zero);
success = LibRyujinxInterop.InitializeGraphics(new GraphicsConfiguration());
var nativeWindowSettings = new NativeWindowSettings()
{
Size = new Vector2i(800, 600),
Title = "Ryujinx",
API = ContextAPI.NoAPI,
IsEventDriven = true,
// This is needed to run on macos
Flags = ContextFlags.ForwardCompatible,
};
using var window = new NativeWindow(nativeWindowSettings);
window.IsVisible = true;
window.Start(args[0]);
}
}
}
}