mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-07-16 18:56:29 +02:00
infra: Make Avalonia the default UI (#6375)
* misc: Move Ryujinx project to Ryujinx.Gtk3 This breaks release CI for now but that's fine. Signed-off-by: Mary Guillemard <mary@mary.zone> * misc: Move Ryujinx.Ava project to Ryujinx This breaks CI for now, but it's fine. Signed-off-by: Mary Guillemard <mary@mary.zone> * infra: Make Avalonia the default UI Should fix CI after the previous changes. GTK3 isn't build by the release job anymore, only by PR CI. This also ensure that the test-ava update package is still generated to allow update from the old testing channel. Signed-off-by: Mary Guillemard <mary@mary.zone> * Fix missing copy in create_app_bundle.sh Signed-off-by: Mary Guillemard <mary@mary.zone> * Fix syntax error Signed-off-by: Mary Guillemard <mary@mary.zone> --------- Signed-off-by: Mary Guillemard <mary@mary.zone>
This commit is contained in:
parent
53b5985da6
commit
ec6cb0abb4
239 changed files with 1235 additions and 1232 deletions
294
src/Ryujinx/UI/Renderer/EmbeddedWindow.cs
Normal file
294
src/Ryujinx/UI/Renderer/EmbeddedWindow.cs
Normal file
|
@ -0,0 +1,294 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Platform;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.UI.Common.Configuration;
|
||||
using Ryujinx.UI.Common.Helper;
|
||||
using SPB.Graphics;
|
||||
using SPB.Platform;
|
||||
using SPB.Platform.GLX;
|
||||
using SPB.Platform.X11;
|
||||
using SPB.Windowing;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading.Tasks;
|
||||
using static Ryujinx.Ava.UI.Helpers.Win32NativeInterop;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Renderer
|
||||
{
|
||||
public class EmbeddedWindow : NativeControlHost
|
||||
{
|
||||
private WindowProc _wndProcDelegate;
|
||||
private string _className;
|
||||
|
||||
protected GLXWindow X11Window { get; set; }
|
||||
|
||||
protected IntPtr WindowHandle { get; set; }
|
||||
protected IntPtr X11Display { get; set; }
|
||||
protected IntPtr NsView { get; set; }
|
||||
protected IntPtr MetalLayer { get; set; }
|
||||
|
||||
public delegate void UpdateBoundsCallbackDelegate(Rect rect);
|
||||
private UpdateBoundsCallbackDelegate _updateBoundsCallback;
|
||||
|
||||
public event EventHandler<IntPtr> WindowCreated;
|
||||
public event EventHandler<Size> BoundsChanged;
|
||||
|
||||
public EmbeddedWindow()
|
||||
{
|
||||
this.GetObservable(BoundsProperty).Subscribe(StateChanged);
|
||||
|
||||
Initialized += OnNativeEmbeddedWindowCreated;
|
||||
}
|
||||
|
||||
public virtual void OnWindowCreated() { }
|
||||
|
||||
protected virtual void OnWindowDestroyed() { }
|
||||
|
||||
protected virtual void OnWindowDestroying()
|
||||
{
|
||||
WindowHandle = IntPtr.Zero;
|
||||
X11Display = IntPtr.Zero;
|
||||
NsView = IntPtr.Zero;
|
||||
MetalLayer = IntPtr.Zero;
|
||||
}
|
||||
|
||||
private void OnNativeEmbeddedWindowCreated(object sender, EventArgs e)
|
||||
{
|
||||
OnWindowCreated();
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
WindowCreated?.Invoke(this, WindowHandle);
|
||||
});
|
||||
}
|
||||
|
||||
private void StateChanged(Rect rect)
|
||||
{
|
||||
BoundsChanged?.Invoke(this, rect.Size);
|
||||
_updateBoundsCallback?.Invoke(rect);
|
||||
}
|
||||
|
||||
protected override IPlatformHandle CreateNativeControlCore(IPlatformHandle control)
|
||||
{
|
||||
if (OperatingSystem.IsLinux())
|
||||
{
|
||||
return CreateLinux(control);
|
||||
}
|
||||
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
return CreateWin32(control);
|
||||
}
|
||||
|
||||
if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
return CreateMacOS();
|
||||
}
|
||||
|
||||
return base.CreateNativeControlCore(control);
|
||||
}
|
||||
|
||||
protected override void DestroyNativeControlCore(IPlatformHandle control)
|
||||
{
|
||||
OnWindowDestroying();
|
||||
|
||||
if (OperatingSystem.IsLinux())
|
||||
{
|
||||
DestroyLinux();
|
||||
}
|
||||
else if (OperatingSystem.IsWindows())
|
||||
{
|
||||
DestroyWin32(control);
|
||||
}
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
DestroyMacOS();
|
||||
}
|
||||
else
|
||||
{
|
||||
base.DestroyNativeControlCore(control);
|
||||
}
|
||||
|
||||
OnWindowDestroyed();
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("linux")]
|
||||
private IPlatformHandle CreateLinux(IPlatformHandle control)
|
||||
{
|
||||
if (ConfigurationState.Instance.Graphics.GraphicsBackend.Value == GraphicsBackend.Vulkan)
|
||||
{
|
||||
X11Window = new GLXWindow(new NativeHandle(X11.DefaultDisplay), new NativeHandle(control.Handle));
|
||||
X11Window.Hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
X11Window = PlatformHelper.CreateOpenGLWindow(new FramebufferFormat(new ColorFormat(8, 8, 8, 0), 16, 0, ColorFormat.Zero, 0, 2, false), 0, 0, 100, 100) as GLXWindow;
|
||||
}
|
||||
|
||||
WindowHandle = X11Window.WindowHandle.RawHandle;
|
||||
X11Display = X11Window.DisplayHandle.RawHandle;
|
||||
|
||||
return new PlatformHandle(WindowHandle, "X11");
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
IPlatformHandle CreateWin32(IPlatformHandle control)
|
||||
{
|
||||
_className = "NativeWindow-" + Guid.NewGuid();
|
||||
|
||||
_wndProcDelegate = delegate (IntPtr hWnd, WindowsMessages msg, IntPtr wParam, IntPtr lParam)
|
||||
{
|
||||
if (VisualRoot != null)
|
||||
{
|
||||
if (msg == WindowsMessages.Lbuttondown ||
|
||||
msg == WindowsMessages.Rbuttondown ||
|
||||
msg == WindowsMessages.Lbuttonup ||
|
||||
msg == WindowsMessages.Rbuttonup ||
|
||||
msg == WindowsMessages.Mousemove)
|
||||
{
|
||||
Point rootVisualPosition = this.TranslatePoint(new Point((long)lParam & 0xFFFF, (long)lParam >> 16 & 0xFFFF), this).Value;
|
||||
Pointer pointer = new(0, PointerType.Mouse, true);
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete (As of Avalonia 11, the constructors for PointerPressedEventArgs & PointerEventArgs are marked as obsolete)
|
||||
switch (msg)
|
||||
{
|
||||
case WindowsMessages.Lbuttondown:
|
||||
case WindowsMessages.Rbuttondown:
|
||||
{
|
||||
bool isLeft = msg == WindowsMessages.Lbuttondown;
|
||||
RawInputModifiers pointerPointModifier = isLeft ? RawInputModifiers.LeftMouseButton : RawInputModifiers.RightMouseButton;
|
||||
PointerPointProperties properties = new(pointerPointModifier, isLeft ? PointerUpdateKind.LeftButtonPressed : PointerUpdateKind.RightButtonPressed);
|
||||
|
||||
var evnt = new PointerPressedEventArgs(
|
||||
this,
|
||||
pointer,
|
||||
this,
|
||||
rootVisualPosition,
|
||||
(ulong)Environment.TickCount64,
|
||||
properties,
|
||||
KeyModifiers.None);
|
||||
|
||||
RaiseEvent(evnt);
|
||||
|
||||
break;
|
||||
}
|
||||
case WindowsMessages.Lbuttonup:
|
||||
case WindowsMessages.Rbuttonup:
|
||||
{
|
||||
bool isLeft = msg == WindowsMessages.Lbuttonup;
|
||||
RawInputModifiers pointerPointModifier = isLeft ? RawInputModifiers.LeftMouseButton : RawInputModifiers.RightMouseButton;
|
||||
PointerPointProperties properties = new(pointerPointModifier, isLeft ? PointerUpdateKind.LeftButtonReleased : PointerUpdateKind.RightButtonReleased);
|
||||
|
||||
var evnt = new PointerReleasedEventArgs(
|
||||
this,
|
||||
pointer,
|
||||
this,
|
||||
rootVisualPosition,
|
||||
(ulong)Environment.TickCount64,
|
||||
properties,
|
||||
KeyModifiers.None,
|
||||
isLeft ? MouseButton.Left : MouseButton.Right);
|
||||
|
||||
RaiseEvent(evnt);
|
||||
|
||||
break;
|
||||
}
|
||||
case WindowsMessages.Mousemove:
|
||||
{
|
||||
var evnt = new PointerEventArgs(
|
||||
PointerMovedEvent,
|
||||
this,
|
||||
pointer,
|
||||
this,
|
||||
rootVisualPosition,
|
||||
(ulong)Environment.TickCount64,
|
||||
new PointerPointProperties(RawInputModifiers.None, PointerUpdateKind.Other),
|
||||
KeyModifiers.None);
|
||||
|
||||
RaiseEvent(evnt);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS0618
|
||||
}
|
||||
}
|
||||
|
||||
return DefWindowProc(hWnd, msg, wParam, lParam);
|
||||
};
|
||||
|
||||
WndClassEx wndClassEx = new()
|
||||
{
|
||||
cbSize = Marshal.SizeOf<WndClassEx>(),
|
||||
hInstance = GetModuleHandle(null),
|
||||
lpfnWndProc = Marshal.GetFunctionPointerForDelegate(_wndProcDelegate),
|
||||
style = ClassStyles.CsOwndc,
|
||||
lpszClassName = Marshal.StringToHGlobalUni(_className),
|
||||
hCursor = CreateArrowCursor(),
|
||||
};
|
||||
|
||||
RegisterClassEx(ref wndClassEx);
|
||||
|
||||
WindowHandle = CreateWindowEx(0, _className, "NativeWindow", WindowStyles.WsChild, 0, 0, 640, 480, control.Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
|
||||
|
||||
Marshal.FreeHGlobal(wndClassEx.lpszClassName);
|
||||
|
||||
return new PlatformHandle(WindowHandle, "HWND");
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("macos")]
|
||||
IPlatformHandle CreateMacOS()
|
||||
{
|
||||
// Create a new CAMetalLayer.
|
||||
ObjectiveC.Object layerObject = new("CAMetalLayer");
|
||||
ObjectiveC.Object metalLayer = layerObject.GetFromMessage("alloc");
|
||||
metalLayer.SendMessage("init");
|
||||
|
||||
// Create a child NSView to render into.
|
||||
ObjectiveC.Object nsViewObject = new("NSView");
|
||||
ObjectiveC.Object child = nsViewObject.GetFromMessage("alloc");
|
||||
child.SendMessage("init", new ObjectiveC.NSRect(0, 0, 0, 0));
|
||||
|
||||
// Make its renderer our metal layer.
|
||||
child.SendMessage("setWantsLayer:", 1);
|
||||
child.SendMessage("setLayer:", metalLayer);
|
||||
metalLayer.SendMessage("setContentsScale:", Program.DesktopScaleFactor);
|
||||
|
||||
// Ensure the scale factor is up to date.
|
||||
_updateBoundsCallback = rect =>
|
||||
{
|
||||
metalLayer.SendMessage("setContentsScale:", Program.DesktopScaleFactor);
|
||||
};
|
||||
|
||||
IntPtr nsView = child.ObjPtr;
|
||||
MetalLayer = metalLayer.ObjPtr;
|
||||
NsView = nsView;
|
||||
|
||||
return new PlatformHandle(nsView, "NSView");
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("Linux")]
|
||||
void DestroyLinux()
|
||||
{
|
||||
X11Window?.Dispose();
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
void DestroyWin32(IPlatformHandle handle)
|
||||
{
|
||||
DestroyWindow(handle.Handle);
|
||||
UnregisterClass(_className, GetModuleHandle(null));
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("macos")]
|
||||
#pragma warning disable CA1822 // Mark member as static
|
||||
void DestroyMacOS()
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
#pragma warning restore CA1822
|
||||
}
|
||||
}
|
94
src/Ryujinx/UI/Renderer/EmbeddedWindowOpenGL.cs
Normal file
94
src/Ryujinx/UI/Renderer/EmbeddedWindowOpenGL.cs
Normal file
|
@ -0,0 +1,94 @@
|
|||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.OpenGL;
|
||||
using Ryujinx.UI.Common.Configuration;
|
||||
using SPB.Graphics;
|
||||
using SPB.Graphics.Exceptions;
|
||||
using SPB.Graphics.OpenGL;
|
||||
using SPB.Platform;
|
||||
using SPB.Platform.WGL;
|
||||
using SPB.Windowing;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Renderer
|
||||
{
|
||||
public class EmbeddedWindowOpenGL : EmbeddedWindow
|
||||
{
|
||||
private SwappableNativeWindowBase _window;
|
||||
|
||||
public OpenGLContextBase Context { get; set; }
|
||||
|
||||
protected override void OnWindowDestroying()
|
||||
{
|
||||
Context.Dispose();
|
||||
|
||||
base.OnWindowDestroying();
|
||||
}
|
||||
|
||||
public override void OnWindowCreated()
|
||||
{
|
||||
base.OnWindowCreated();
|
||||
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
_window = new WGLWindow(new NativeHandle(WindowHandle));
|
||||
}
|
||||
else if (OperatingSystem.IsLinux())
|
||||
{
|
||||
_window = X11Window;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
var flags = OpenGLContextFlags.Compat;
|
||||
if (ConfigurationState.Instance.Logger.GraphicsDebugLevel != GraphicsDebugLevel.None)
|
||||
{
|
||||
flags |= OpenGLContextFlags.Debug;
|
||||
}
|
||||
|
||||
var graphicsMode = Environment.OSVersion.Platform == PlatformID.Unix ? new FramebufferFormat(new ColorFormat(8, 8, 8, 0), 16, 0, ColorFormat.Zero, 0, 2, false) : FramebufferFormat.Default;
|
||||
|
||||
Context = PlatformHelper.CreateOpenGLContext(graphicsMode, 3, 3, flags);
|
||||
|
||||
Context.Initialize(_window);
|
||||
Context.MakeCurrent(_window);
|
||||
|
||||
GL.LoadBindings(new OpenTKBindingsContext(Context.GetProcAddress));
|
||||
|
||||
Context.MakeCurrent(null);
|
||||
}
|
||||
|
||||
public void MakeCurrent(bool unbind = false, bool shouldThrow = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
Context?.MakeCurrent(!unbind ? _window : null);
|
||||
}
|
||||
catch (ContextException e)
|
||||
{
|
||||
if (shouldThrow)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
Logger.Warning?.Print(LogClass.UI, $"Failed to {(!unbind ? "bind" : "unbind")} OpenGL context: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
public void SwapBuffers()
|
||||
{
|
||||
_window?.SwapBuffers();
|
||||
}
|
||||
|
||||
public void InitializeBackgroundContext(IRenderer renderer)
|
||||
{
|
||||
(renderer as OpenGLRenderer)?.InitializeBackgroundContext(SPBOpenGLContext.CreateBackgroundContext(Context));
|
||||
|
||||
MakeCurrent();
|
||||
}
|
||||
}
|
||||
}
|
42
src/Ryujinx/UI/Renderer/EmbeddedWindowVulkan.cs
Normal file
42
src/Ryujinx/UI/Renderer/EmbeddedWindowVulkan.cs
Normal file
|
@ -0,0 +1,42 @@
|
|||
using Silk.NET.Vulkan;
|
||||
using SPB.Graphics.Vulkan;
|
||||
using SPB.Platform.Metal;
|
||||
using SPB.Platform.Win32;
|
||||
using SPB.Platform.X11;
|
||||
using SPB.Windowing;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Renderer
|
||||
{
|
||||
public class EmbeddedWindowVulkan : EmbeddedWindow
|
||||
{
|
||||
public SurfaceKHR CreateSurface(Instance instance)
|
||||
{
|
||||
NativeWindowBase nativeWindowBase;
|
||||
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
nativeWindowBase = new SimpleWin32Window(new NativeHandle(WindowHandle));
|
||||
}
|
||||
else if (OperatingSystem.IsLinux())
|
||||
{
|
||||
nativeWindowBase = new SimpleX11Window(new NativeHandle(X11Display), new NativeHandle(WindowHandle));
|
||||
}
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
nativeWindowBase = new SimpleMetalWindow(new NativeHandle(NsView), new NativeHandle(MetalLayer));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
return new SurfaceKHR((ulong?)VulkanHelper.CreateWindowSurface(instance.Handle, nativeWindowBase));
|
||||
}
|
||||
|
||||
public SurfaceKHR CreateSurface(Instance instance, Vk _)
|
||||
{
|
||||
return CreateSurface(instance);
|
||||
}
|
||||
}
|
||||
}
|
20
src/Ryujinx/UI/Renderer/OpenTKBindingsContext.cs
Normal file
20
src/Ryujinx/UI/Renderer/OpenTKBindingsContext.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
using OpenTK;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Renderer
|
||||
{
|
||||
internal class OpenTKBindingsContext : IBindingsContext
|
||||
{
|
||||
private readonly Func<string, IntPtr> _getProcAddress;
|
||||
|
||||
public OpenTKBindingsContext(Func<string, IntPtr> getProcAddress)
|
||||
{
|
||||
_getProcAddress = getProcAddress;
|
||||
}
|
||||
|
||||
public IntPtr GetProcAddress(string procName)
|
||||
{
|
||||
return _getProcAddress(procName);
|
||||
}
|
||||
}
|
||||
}
|
12
src/Ryujinx/UI/Renderer/RendererHost.axaml
Normal file
12
src/Ryujinx/UI/Renderer/RendererHost.axaml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<UserControl
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
d:DesignWidth="800"
|
||||
d:DesignHeight="450"
|
||||
x:Class="Ryujinx.Ava.UI.Renderer.RendererHost"
|
||||
FlowDirection="LeftToRight"
|
||||
Focusable="True">
|
||||
</UserControl>
|
68
src/Ryujinx/UI/Renderer/RendererHost.axaml.cs
Normal file
68
src/Ryujinx/UI/Renderer/RendererHost.axaml.cs
Normal file
|
@ -0,0 +1,68 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.UI.Common.Configuration;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Renderer
|
||||
{
|
||||
public partial class RendererHost : UserControl, IDisposable
|
||||
{
|
||||
public readonly EmbeddedWindow EmbeddedWindow;
|
||||
|
||||
public event EventHandler<EventArgs> WindowCreated;
|
||||
public event Action<object, Size> BoundsChanged;
|
||||
|
||||
public RendererHost()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
if (ConfigurationState.Instance.Graphics.GraphicsBackend.Value == GraphicsBackend.OpenGl)
|
||||
{
|
||||
EmbeddedWindow = new EmbeddedWindowOpenGL();
|
||||
}
|
||||
else
|
||||
{
|
||||
EmbeddedWindow = new EmbeddedWindowVulkan();
|
||||
}
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
EmbeddedWindow.WindowCreated += CurrentWindow_WindowCreated;
|
||||
EmbeddedWindow.BoundsChanged += CurrentWindow_BoundsChanged;
|
||||
|
||||
Content = EmbeddedWindow;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (EmbeddedWindow != null)
|
||||
{
|
||||
EmbeddedWindow.WindowCreated -= CurrentWindow_WindowCreated;
|
||||
EmbeddedWindow.BoundsChanged -= CurrentWindow_BoundsChanged;
|
||||
}
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
|
||||
{
|
||||
base.OnDetachedFromVisualTree(e);
|
||||
|
||||
Dispose();
|
||||
}
|
||||
|
||||
private void CurrentWindow_BoundsChanged(object sender, Size e)
|
||||
{
|
||||
BoundsChanged?.Invoke(sender, e);
|
||||
}
|
||||
|
||||
private void CurrentWindow_WindowCreated(object sender, IntPtr e)
|
||||
{
|
||||
WindowCreated?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
49
src/Ryujinx/UI/Renderer/SPBOpenGLContext.cs
Normal file
49
src/Ryujinx/UI/Renderer/SPBOpenGLContext.cs
Normal file
|
@ -0,0 +1,49 @@
|
|||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Graphics.OpenGL;
|
||||
using SPB.Graphics;
|
||||
using SPB.Graphics.OpenGL;
|
||||
using SPB.Platform;
|
||||
using SPB.Windowing;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Renderer
|
||||
{
|
||||
class SPBOpenGLContext : IOpenGLContext
|
||||
{
|
||||
private readonly OpenGLContextBase _context;
|
||||
private readonly NativeWindowBase _window;
|
||||
|
||||
private SPBOpenGLContext(OpenGLContextBase context, NativeWindowBase window)
|
||||
{
|
||||
_context = context;
|
||||
_window = window;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_context.Dispose();
|
||||
_window.Dispose();
|
||||
}
|
||||
|
||||
public void MakeCurrent()
|
||||
{
|
||||
_context.MakeCurrent(_window);
|
||||
}
|
||||
|
||||
public bool HasContext() => _context.IsCurrent;
|
||||
|
||||
public static SPBOpenGLContext CreateBackgroundContext(OpenGLContextBase sharedContext)
|
||||
{
|
||||
OpenGLContextBase context = PlatformHelper.CreateOpenGLContext(FramebufferFormat.Default, 3, 3, OpenGLContextFlags.Compat, true, sharedContext);
|
||||
NativeWindowBase window = PlatformHelper.CreateOpenGLWindow(FramebufferFormat.Default, 0, 0, 100, 100);
|
||||
|
||||
context.Initialize(window);
|
||||
context.MakeCurrent(window);
|
||||
|
||||
GL.LoadBindings(new OpenTKBindingsContext(context.GetProcAddress));
|
||||
|
||||
context.MakeCurrent(null);
|
||||
|
||||
return new SPBOpenGLContext(context, window);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue