diff options
author | TSR Berry <20988865+TSRBerry@users.noreply.github.com> | 2023-04-08 01:22:00 +0200 |
---|---|---|
committer | Mary <thog@protonmail.com> | 2023-04-27 23:51:14 +0200 |
commit | cee712105850ac3385cd0091a923438167433f9f (patch) | |
tree | 4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /src/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs | |
parent | cd124bda587ef09668a971fa1cac1c3f0cfc9f21 (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.cs | 169 |
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 |