aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx/Ui/GLRenderer.cs
blob: 06d414edcabc7c904cfd15a42d282a01b9525e40 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
using OpenTK.Graphics.OpenGL;
using Ryujinx.Common.Configuration;
using Ryujinx.Graphics.OpenGL;
using Ryujinx.Input.HLE;
using SPB.Graphics;
using SPB.Graphics.OpenGL;
using SPB.Platform;
using SPB.Platform.GLX;
using SPB.Platform.WGL;
using SPB.Windowing;
using System;
using System.Runtime.InteropServices;

namespace Ryujinx.Ui
{
    public class GlRenderer : RendererWidgetBase
    {
        private GraphicsDebugLevel _glLogLevel;

        private bool _initializedOpenGL;

        private OpenGLContextBase _openGLContext;
        private SwappableNativeWindowBase _nativeWindow;

        public GlRenderer(InputManager inputManager, GraphicsDebugLevel glLogLevel) : base(inputManager, glLogLevel)
        {
            _glLogLevel = glLogLevel;
        }

        protected override bool OnDrawn(Cairo.Context cr)
        {
            if (!_initializedOpenGL)
            {
                IntializeOpenGL();
            }

            return true;
        }

        private void IntializeOpenGL()
        {
            _nativeWindow = RetrieveNativeWindow();

            Window.EnsureNative();

            _openGLContext = PlatformHelper.CreateOpenGLContext(GetGraphicsMode(), 3, 3, _glLogLevel == GraphicsDebugLevel.None ? OpenGLContextFlags.Compat : OpenGLContextFlags.Compat | OpenGLContextFlags.Debug);
            _openGLContext.Initialize(_nativeWindow);
            _openGLContext.MakeCurrent(_nativeWindow);

            // Release the GL exclusivity that SPB gave us as we aren't going to use it in GTK Thread.
            _openGLContext.MakeCurrent(null);

            WaitEvent.Set();

            _initializedOpenGL = true;
        }

        private SwappableNativeWindowBase RetrieveNativeWindow()
        {
            if (OperatingSystem.IsWindows())
            {
                IntPtr windowHandle = gdk_win32_window_get_handle(Window.Handle);

                return new WGLWindow(new NativeHandle(windowHandle));
            }
            else if (OperatingSystem.IsLinux())
            {
                IntPtr displayHandle = gdk_x11_display_get_xdisplay(Display.Handle);
                IntPtr windowHandle = gdk_x11_window_get_xid(Window.Handle);

                return new GLXWindow(new NativeHandle(displayHandle), new NativeHandle(windowHandle));
            }

            throw new NotImplementedException();
        }

        [DllImport("libgdk-3-0.dll")]
        private static extern IntPtr gdk_win32_window_get_handle(IntPtr d);

        [DllImport("libgdk-3.so.0")]
        private static extern IntPtr gdk_x11_display_get_xdisplay(IntPtr gdkDisplay);

        [DllImport("libgdk-3.so.0")]
        private static extern IntPtr gdk_x11_window_get_xid(IntPtr gdkWindow);

        private static FramebufferFormat GetGraphicsMode()
        {
            return Environment.OSVersion.Platform == PlatformID.Unix ? new FramebufferFormat(new ColorFormat(8, 8, 8, 0), 16, 0, ColorFormat.Zero, 0, 2, false) : FramebufferFormat.Default;
        }

        public override void InitializeRenderer()
        {
            // First take exclusivity on the OpenGL context.
            ((OpenGLRenderer)Renderer).InitializeBackgroundContext(SPBOpenGLContext.CreateBackgroundContext(_openGLContext));

            _openGLContext.MakeCurrent(_nativeWindow);

            GL.ClearColor(0, 0, 0, 1.0f);
            GL.Clear(ClearBufferMask.ColorBufferBit);
            SwapBuffers();
        }

        public override void SwapBuffers()
        {
            _nativeWindow.SwapBuffers();
        }

        protected override string GetGpuBackendName()
        {
            return "OpenGL";
        }

        protected override void Dispose(bool disposing)
        {
            // Try to bind the OpenGL context before calling the shutdown event
            try
            {
                _openGLContext?.MakeCurrent(_nativeWindow);
            }
            catch (Exception) { }

            Device.DisposeGpu();
            NpadManager.Dispose();

            // Unbind context and destroy everything
            try
            {
                _openGLContext?.MakeCurrent(null);
            }
            catch (Exception) { }

            _openGLContext.Dispose();
        }
    }
}