aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs
diff options
context:
space:
mode:
authorTSR Berry <20988865+TSRBerry@users.noreply.github.com>2023-04-08 01:22:00 +0200
committerMary <thog@protonmail.com>2023-04-27 23:51:14 +0200
commitcee712105850ac3385cd0091a923438167433f9f (patch)
tree4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /src/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs
parentcd124bda587ef09668a971fa1cac1c3f0cfc9f21 (diff)
Move solution and projects to src
Diffstat (limited to 'src/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs')
-rw-r--r--src/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs169
1 files changed, 169 insertions, 0 deletions
diff --git a/src/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs b/src/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs
new file mode 100644
index 00000000..69b0f42f
--- /dev/null
+++ b/src/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs
@@ -0,0 +1,169 @@
+using OpenTK;
+using OpenTK.Graphics.OpenGL;
+using Ryujinx.Common.Configuration;
+using Ryujinx.Common.Logging;
+using Ryujinx.Graphics.OpenGL;
+using Ryujinx.Input.HLE;
+using System;
+using static SDL2.SDL;
+
+namespace Ryujinx.Headless.SDL2.OpenGL
+{
+ class OpenGLWindow : WindowBase
+ {
+ private static void SetupOpenGLAttributes(bool sharedContext, GraphicsDebugLevel debugLevel)
+ {
+ SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+ SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_CONTEXT_MINOR_VERSION, 3);
+ SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_CONTEXT_PROFILE_MASK, SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
+ SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_CONTEXT_FLAGS, debugLevel != GraphicsDebugLevel.None ? (int)SDL_GLcontext.SDL_GL_CONTEXT_DEBUG_FLAG : 0);
+ SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_SHARE_WITH_CURRENT_CONTEXT, sharedContext ? 1 : 0);
+
+ SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_ACCELERATED_VISUAL, 1);
+ SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_RED_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_GREEN_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_BLUE_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_ALPHA_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_DEPTH_SIZE, 16);
+ SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_STENCIL_SIZE, 0);
+ SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_DOUBLEBUFFER, 1);
+ SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_STEREO, 0);
+ }
+
+ private class OpenToolkitBindingsContext : IBindingsContext
+ {
+ public IntPtr GetProcAddress(string procName)
+ {
+ return SDL_GL_GetProcAddress(procName);
+ }
+ }
+
+ private class SDL2OpenGLContext : IOpenGLContext
+ {
+ private IntPtr _context;
+ private IntPtr _window;
+ private bool _shouldDisposeWindow;
+
+ public SDL2OpenGLContext(IntPtr context, IntPtr window, bool shouldDisposeWindow = true)
+ {
+ _context = context;
+ _window = window;
+ _shouldDisposeWindow = shouldDisposeWindow;
+ }
+
+ public static SDL2OpenGLContext CreateBackgroundContext(SDL2OpenGLContext sharedContext)
+ {
+ sharedContext.MakeCurrent();
+
+ // Ensure we share our contexts.
+ SetupOpenGLAttributes(true, GraphicsDebugLevel.None);
+ IntPtr windowHandle = SDL_CreateWindow("Ryujinx background context window", 0, 0, 1, 1, SDL_WindowFlags.SDL_WINDOW_OPENGL | SDL_WindowFlags.SDL_WINDOW_HIDDEN);
+ IntPtr context = SDL_GL_CreateContext(windowHandle);
+
+ GL.LoadBindings(new OpenToolkitBindingsContext());
+
+ SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 0);
+
+ SDL_GL_MakeCurrent(windowHandle, IntPtr.Zero);
+
+ return new SDL2OpenGLContext(context, windowHandle);
+ }
+
+ public void MakeCurrent()
+ {
+ if (SDL_GL_GetCurrentContext() == _context || SDL_GL_GetCurrentWindow() == _window)
+ {
+ return;
+ }
+
+ int res = SDL_GL_MakeCurrent(_window, _context);
+
+ if (res != 0)
+ {
+ string errorMessage = $"SDL_GL_CreateContext failed with error \"{SDL_GetError()}\"";
+
+ Logger.Error?.Print(LogClass.Application, errorMessage);
+
+ throw new Exception(errorMessage);
+ }
+ }
+
+ public void Dispose()
+ {
+ SDL_GL_DeleteContext(_context);
+
+ if (_shouldDisposeWindow)
+ {
+ SDL_DestroyWindow(_window);
+ }
+ }
+ }
+
+ private GraphicsDebugLevel _glLogLevel;
+ private SDL2OpenGLContext _openGLContext;
+
+ public OpenGLWindow(
+ InputManager inputManager,
+ GraphicsDebugLevel glLogLevel,
+ AspectRatio aspectRatio,
+ bool enableMouse,
+ HideCursor hideCursor)
+ : base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursor)
+ {
+ _glLogLevel = glLogLevel;
+ }
+
+ public override SDL_WindowFlags GetWindowFlags() => SDL_WindowFlags.SDL_WINDOW_OPENGL;
+
+ protected override void InitializeWindowRenderer()
+ {
+ // Ensure to not share this context with other contexts before this point.
+ SetupOpenGLAttributes(false, _glLogLevel);
+ IntPtr context = SDL_GL_CreateContext(WindowHandle);
+ SDL_GL_SetSwapInterval(1);
+
+ if (context == IntPtr.Zero)
+ {
+ string errorMessage = $"SDL_GL_CreateContext failed with error \"{SDL_GetError()}\"";
+
+ Logger.Error?.Print(LogClass.Application, errorMessage);
+
+ throw new Exception(errorMessage);
+ }
+
+ // NOTE: The window handle needs to be disposed by the thread that created it and is handled separately.
+ _openGLContext = new SDL2OpenGLContext(context, WindowHandle, false);
+
+ // First take exclusivity on the OpenGL context.
+ ((OpenGLRenderer)Renderer).InitializeBackgroundContext(SDL2OpenGLContext.CreateBackgroundContext(_openGLContext));
+
+ _openGLContext.MakeCurrent();
+
+ GL.ClearColor(0, 0, 0, 1.0f);
+ GL.Clear(ClearBufferMask.ColorBufferBit);
+ SwapBuffers();
+
+ Renderer?.Window.SetSize(DefaultWidth, DefaultHeight);
+ MouseDriver.SetClientSize(DefaultWidth, DefaultHeight);
+ }
+
+ protected override void InitializeRenderer() { }
+
+ protected override void FinalizeWindowRenderer()
+ {
+ // Try to bind the OpenGL context before calling the gpu disposal.
+ _openGLContext.MakeCurrent();
+
+ Device.DisposeGpu();
+
+ // Unbind context and destroy everything
+ SDL_GL_MakeCurrent(WindowHandle, IntPtr.Zero);
+ _openGLContext.Dispose();
+ }
+
+ protected override void SwapBuffers()
+ {
+ SDL_GL_SwapWindow(WindowHandle);
+ }
+ }
+} \ No newline at end of file